Java和ABAP的垃圾回收机制(Garbage Collection)比较
Both Java and ABAP can support automatic garbage collection. As an application developer the GC process are completely transparent for us and in our application code most of the time we should never call the GC API provided by Java or ABAP. Nevertheless it helps us to write more robust code with comparatively lower memory consumption if we have some basic understanding about the trigger point of Garbage collection.
Garbage Collection in Java
Use this small code below for test, which allocates 2MB memory every 100 millisecond.
package memoryTest;
import java.util.Timer;
import java.util.TimerTask;
class MyTask extends TimerTask{
static final int MB = * ;
@Override
public void run() {
byte[] a1 = new byte[ * MB];
a1[] = ;
Runtime runtime = Runtime.getRuntime();
System.out.print("total :" + (runtime.totalMemory() / )+ " KBn");
long free = runtime.freeMemory() / ;
System.out.print("free:" + free+ " KBn");
}
}
public class MemoryAllocationTest {
static public void main(String[] arg){
Timer timer = new Timer();
timer.schedule(new MyTask(), , );
}
}
Minor Garbage Collection in Java
Execute the program with the following VM argument. The option PrintGCDetails can print out GC execution detail and Xmx40m means the max allowed heap allocation size is 40MB.
When executing you can find following output in console:
total :39424 KB free:35720 KB total :39424 KB free:33672 KB total :39424 KB free:31624 KB total :39424 KB free:29576 KB [GC (Allocation Failure) [PSYoungGen: 9847K->744K(11776K)] 9847K->752K(39424K), 0.0022270 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] total :39424 KB free:36457 KB total :39424 KB free:34409 KB total :39424 KB free:32361 KB total :39424 KB free:30313 KB [GC (Allocation Failure) [PSYoungGen: 9102K->616K(11776K)] 9110K->632K(39424K), 0.0018849 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] total :39424 KB free:36564 KB The GC log clearly shows that every time JVM fails to find a proper memory area in young generation, a GC operation is launched AUTOMATICALLY.
Let’s analyze the log: [GC (Allocation Failure) [PSYoungGen: 9847K->744K(11776K)] 9847K->752K(39424K), 0.0022270 secs]
Some knowledge to understand this log
From Java official website we know the Heap in Hotspot( one kind of JVM ) consists of Young Generation, Old Generation and Permanent Generation. ( Reminder: Permanent Generation is removed from Java 8, Metaspace is introduced instead )
The Young Generation is where all new objects are allocated and aged. When the young generation fills up, this causes a minor garbage collection. This GC could be observed in our log that once GC is done, the free space size in young generation increases greatly.
All minor garbage collections are “Stop the World” events. This means that all application threads are stopped until the operation completes. The time spent on GC is also printed in the log, in our example:
Full Garbage Collection in Java
Now let’s do some change on the source code. This time I allocate 1GB instead.
VM argument is changed to -Xmx6000m accordingly.
Log:
total :1525248 KB free:488140 KB total :2549760 KB free:488652 KB total :3574272 KB free:489164 KB [GC (Allocation Failure) [PSYoungGen: 13107K->632K(152576K)] 3085107K->3072640K(4248576K), 0.0246054 secs] [Times: user=0.13 sys=0.00, real=0.02 secs] [GC (Allocation Failure) [PSYoungGen: 632K->664K(283648K)] 3072640K->3072672K(4379648K), 0.0243200 secs] [Times: user=0.25 sys=0.00, real=0.03 secs] [Full GC (Allocation Failure) [PSYoungGen: 664K->0K(283648K)] [ParOldGen: 3072008K->539K(268800K)] 3072672K->539K(552448K), [Metaspace: 2662K->2662K(1056768K)], 0.2419282 secs] [Times: user=0.11 sys=0.22, real=0.24 secs] total :1576960 KB free:547177 KB total :2601472 KB free:547689 KB total :3625984 KB free:548201 KB [GC (Allocation Failure) [PSYoungGen: 5242K->0K(283648K)] 3077782K->3072539K(4379648K), 0.0127622 secs] [Times: user=0.03 sys=0.00, real=0.01 secs] [GC (Allocation Failure) [PSYoungGen: 0K->0K(521728K)] 3072539K->3072539K(4617728K), 0.0115785 secs] [Times: user=0.13 sys=0.00, real=0.01 secs] [Full GC (Allocation Failure) [PSYoungGen: 0K->0K(521728K)] [ParOldGen: 3072539K->1024K(275456K)] 3072539K->1024K(797184K), [Metaspace: 2662K->2662K(1056768K)], 0.2102163 secs] [Times: user=0.03 sys=0.17, real=0.21 secs] total :1821696 KB
The last test in Java
Now I change option Xmx6000m to Xmx900m, and OutOfMemoryError exception is raised as expected. From the log we know that GC still tried it best to find available memory for allocation but failed.
Garbage Collection in ABAP
Execute the following program twice, the first time with manual clear = abap_false and the second time abap_true.
PARAMETERS: clear TYPE c as CHECKBOX DEFAULT abap_false.
TYPES: tt_table TYPE TABLE OF tadir WITH KEY pgmid object.
DATA: lt_result TYPE TABLE OF tadir,
lt_total TYPE TABLE OF tadir,
lr_result TYPE REF TO tt_table.
DATA: c1 TYPE cursor.
OPEN CURSOR @c1 FOR SELECT * FROM tadir.
DO.
WRITE: / |Round: { sy-index } | COLOR COL_NEGATIVE.
CREATE DATA lr_result.
FETCH NEXT CURSOR @c1 INTO TABLE @lr_result->* PACKAGE SIZE 800000.
IF sy-subrc <> 0.
EXIT.
ENDIF.
APPEND LINES OF lr_result->* TO lt_total.
cl_abap_memory_utilities=>get_memory_size_of_object( EXPORTING object = lt_total
IMPORTING
bound_size_alloc = DATA(bound_alloc)
bound_size_used = DATA(bound_used) ).
WRITE: / 'bound alloc:' , bound_alloc.
WRITE: / 'bound used:' , bound_used.
cl_abap_memory_utilities=>get_total_used_size( IMPORTING size = DATA(lv_before_size) ).
WRITE: / |Total size before GC: { lv_before_size }| COLOR COL_POSITIVE.
IF clear = abap_true.
CLEAR: lr_result->*, lt_result, lr_result.
ENDIF.
cl_abap_memory_utilities=>do_garbage_collection( ).
cl_abap_memory_utilities=>get_total_used_size( IMPORTING size = DATA(lv_after_size) ).
WRITE: / |Total size after GC: { lv_after_size }| COLOR COL_GROUP.
DATA(rate) = ( lv_before_size - lv_after_size ) * 100 / lv_before_size.
WRITE: / |Freed rate: { rate }%| COLOR COL_TOTAL.
ENDDO.
WRITE: / lines( lt_total ).
Compare the output of two execution we find out the final filled result, lt_total, are equal for both execution. And the temporary variable lr_result->*, lt_result and lr_result used to store the data queried from database table during each iteration are useless once the content are appended to the final result internal table, so in principle they are ok to be cleared manually. The comparison shows that if within a LOOP you have local variable which holds a large amount of data which is only handled in current loop, then you can manually clear it before the next round of loop starts to free up memory.
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vehtBAFO-1598236863158)(https://upload-images.jianshu.io/upload_images/2085791-f48a0fb39770eaa8.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)]
You may argue that does the line below really take effect during the comparison?
cl_abap_memory_utilities=>do_garbage_collection( ).
Good question! If it is commented out and execute report with manual clear = abap_true, still the same output will be printed out as before it is commented out. So let’s look at another example:
REPORT z.
PARAMETERS: call_gc type char1 as CHECKBOX DEFAULT abap_false.
class lcl_memory_test DEFINITION.
public SECTION.
methods: constructor.
PRIVATE SECTION.
data: mt_data type TABLE OF tadir.
endclass.
class lcl_memory_test IMPLEMENTATION.
method: constructor.
SELECT * INTO TABLE mt_data FROM tadir.
endmethod.
endclass.
START-OF-SELECTION.
data(lo_class) = new lcl_memory_test( ).
cl_abap_memory_utilities=>get_total_used_size( IMPORTING size = DATA(lv_before_size) ).
WRITE: / |Total size before GC: { lv_before_size }| COLOR COL_POSITIVE.
CLEAR: lo_class.
IF call_gc = abap_true.
cl_abap_memory_utilities=>do_garbage_collection( ).
ENDIF.
cl_abap_memory_utilities=>get_total_used_size( IMPORTING size = DATA(lv_after_size) ).
WRITE: / |Total size after GC: { lv_after_size }| COLOR COL_GROUP.
DATA(rate) = ( lv_before_size - lv_after_size ) * 100 / lv_before_size.
WRITE: / |Freed rate: { rate }%| COLOR COL_TOTAL.
This time I wrap the code to manually trigger GC with a switch call_gc:
Execute it first with call_gc = abap_false, and the result shows even though you have manually clear the reference of lo_class, still no memory is free up.
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OoCoEmUZ-1598236863159)(https://upload-images.jianshu.io/upload_images/2085791-3f0498690e66df0a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)]
And the second time call_gc = true. The GC processor has done a good job!
Last but not least, the purpose of this ABAP example is not asking you to call GC API manually in your application code, conversely, you should always avoid to do that.
- Android调用系统相册和拍照的Demo
- 黑客是如何通过RDP远程桌面服务进行攻击的
- SDL的几个宽高概念讲解(文中有福利)
- [安全科普]你必须了解的session的本质
- Android中如何动态的实现设置全屏和退出全屏
- Android 双进程Service常驻后台,无惧“一键清理”
- Android之捕获TextView超链接
- 自封装Android软键盘工具类ImeUtil
- XSS挑战第一期Writeup
- 安全公司新星Aorato推出“行为防火墙”
- 倍数提高工作效率的 Android Studio 奇技
- xss如何加载远程js的一些tips
- Android中如何实现图文混排
- Jenkins 创始人:持续交付的 What、Why 及 How
- java教程
- Java快速入门
- Java 开发环境配置
- Java基本语法
- Java 对象和类
- Java 基本数据类型
- Java 变量类型
- Java 修饰符
- Java 运算符
- Java 循环结构
- Java 分支结构
- Java Number类
- Java Character类
- Java String类
- Java StringBuffer和StringBuilder类
- Java 数组
- Java 日期时间
- Java 正则表达式
- Java 方法
- Java 流(Stream)、文件(File)和IO
- Java 异常处理
- Java 继承
- Java 重写(Override)与重载(Overload)
- Java 多态
- Java 抽象类
- Java 封装
- Java 接口
- Java 包(package)
- Java 数据结构
- Java 集合框架
- Java 泛型
- Java 序列化
- Java 网络编程
- Java 发送邮件
- Java 多线程编程
- Java Applet基础
- Java 文档注释
- 【服务网格架构】Envoy架构概览(7):断路,全局限速和TLS
- 你的消息队列如何保证消息不丢失,且只被消费一次,这篇就教会你
- 【服务网格架构】Envoy架构概览(9):访问日志,MongoDB,DynamoDB,Redis
- Redis Cluster 原理分析
- Ceph介绍及原理架构分享
- 分布式存储Ceph之PG状态详解
- JS中的事件循环机制与宏队列、微队列笔记
- Redis 哨兵机制以及底层原理深入解析,这次终于搞清楚了
- SQL 找出分组中具有极值的行
- 接入层Nginx架构及模块介绍分享
- 【问题修复】mds0: Metadata damage detected
- 【服务网格架构】Envoy架构概览(6):异常检测
- 分布式存储Cephfs读取优化方案
- SQL 确定序列里缺失值的范围
- 【问题修复】osd自杀问题跟踪