有关JVM的GC问题

lyfree 发布于 2013/11/27 23:35
阅读 641
收藏 2
import java.util.ArrayList;  
import java.util.List;  
  
public class Test {  
  
    private byte[] buffer;  
    private List ls;  
  
    public Test() {  
        this.buffer = new byte[4 * 1024 * 1024];  
        this.ls = new ArrayList();  
    }  
  
    private List getList() {  
        return ls;  
    }  
  
    public static void main(String[] args) {  
        Test t1 = new Test();  
        Test t2 = new Test();  
        t1.getList().add(t2);  
        t2.getList().add(t1);  
        t1 = t2 = null;  
        Test t3 = new Test(); 
        System.gc();
        System.out.println(t3);  
    }  

}

用以下参数运行java -Xms10M -Xmx10M Test,将jvm的大小设置为10M,不允许扩展,按引用计数法,t1和t2相互引用,他们的引用计数都不可能为0,那么他们将永远不会回收,在我的环境中JVM共10M,t1 t2占用8m,如果是引用计数那么剩下的2M,是不足以创建t3的,会抛出异常。我运行时果然抛出了异常,难道这说明我的JVM真的用的引用计数进行垃圾回收的?(我用的是java version "1.7.0_10" Java HotSpot(TM) Client VM),求解释哦!

加载中
0
excepiton
excepiton

以下是运行的时候堆分析

try{
    Thread.sleep(100000000);
}catch(Exception e){
}
Test t1 = new Test();   
Test t2 = new Test(); 



C:\Users\Administrator>jmap -heap 5028
Attaching to process ID 5028, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 24.45-b08

using thread-local object allocation.
Parallel GC with 4 thread(s)

Heap Configuration:
   MinHeapFreeRatio = 40
   MaxHeapFreeRatio = 70
   MaxHeapSize      = 10485760 (10.0MB)
   NewSize          = 1310720 (1.25MB)
   MaxNewSize       = 17592186044415 MB
   OldSize          = 5439488 (5.1875MB)
   NewRatio         = 2
   SurvivorRatio    = 8
   PermSize         = 21757952 (20.75MB)
   MaxPermSize      = 85983232 (82.0MB)
   G1HeapRegionSize = 0 (0.0MB)

Heap Usage:
PS Young Generation
Eden Space:
   capacity = 2621440 (2.5MB)
   used     = 678072 (0.6466598510742188MB)
   free     = 1943368 (1.8533401489257812MB)
   25.86639404296875% used
From Space:
   capacity = 524288 (0.5MB)
   used     = 0 (0.0MB)
   free     = 524288 (0.5MB)
   0.0% used
To Space:
   capacity = 524288 (0.5MB)
   used     = 0 (0.0MB)
   free     = 524288 (0.5MB)
   0.0% used
PS Old Generation
   capacity = 7340032 (7.0MB)
   used     = 0 (0.0MB)
   free     = 7340032 (7.0MB)
   0.0% used
PS Perm Generation
   capacity = 22020096 (21.0MB)
   used     = 2488384 (2.37310791015625MB)
   free     = 19531712 (18.62689208984375MB)
   11.300513857886905% used



可以看出Old Gen 只有7M,你t2 new的时候内存已经不足了。

Test t1 = new Test(); 
try{
    Thread.sleep(100000000);
}catch(Exception e){
}  
Test t2 = new Test(); 



C:\Users\Administrator>jmap -heap 3356
Attaching to process ID 3356, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 24.45-b08

using thread-local object allocation.
Parallel GC with 4 thread(s)

Heap Configuration:
   MinHeapFreeRatio = 40
   MaxHeapFreeRatio = 70
   MaxHeapSize      = 10485760 (10.0MB)
   NewSize          = 1310720 (1.25MB)
   MaxNewSize       = 17592186044415 MB
   OldSize          = 5439488 (5.1875MB)
   NewRatio         = 2
   SurvivorRatio    = 8
   PermSize         = 21757952 (20.75MB)
   MaxPermSize      = 85983232 (82.0MB)
   G1HeapRegionSize = 0 (0.0MB)

Heap Usage:
PS Young Generation
Eden Space:
   capacity = 2621440 (2.5MB)
   used     = 678072 (0.6466598510742188MB)
   free     = 1943368 (1.8533401489257812MB)
   25.86639404296875% used
From Space:
   capacity = 524288 (0.5MB)
   used     = 0 (0.0MB)
   free     = 524288 (0.5MB)
   0.0% used
To Space:
   capacity = 524288 (0.5MB)
   used     = 0 (0.0MB)
   free     = 524288 (0.5MB)
   0.0% used
PS Old Generation
   capacity = 7340032 (7.0MB)
   used     = 4194320 (4.0000152587890625MB)
   free     = 3145712 (2.9999847412109375MB)
   57.143075125558035% used
PS Perm Generation
   capacity = 22020096 (21.0MB)
   used     = 2488392 (2.3731155395507812MB)
   free     = 19531704 (18.62688446044922MB)
   11.300550188337054% used

1501 interned Strings occupying 138800 bytes.



李国刚
李国刚
nice work!用 dump oom error是一种好的分析方法,也可以,用jstat,debug分析,看old和new的使用情况!当然还可以用其他分享工具!
1
李国刚
李国刚

java gc不是引用计数, 是根搜索法确定是否可以回收!

第二System.gc()有没有都没有关系,java会在 heap不够分配的时候触发gc。

第三,理论这不会oom,因为java是能够回收t1,t2。我在 win java version "1.6.0_07"
Java(TM) SE Runtime Environment (build 1.6.0_07-b06)
Java HotSpot(TM) Client VM (build 10.0-b23, mixed mode, sharing)

运行也确实没有oom。去掉t1=t2=null,会heap oom 

第四,java不是 你new byte[4 * 1024 * 1024]这么大,就是占用这么多内存,实际会比这个大,因为还有object header,object的一些占用,字节对齐等!

下午回来在测试下你说的,你是在win上运行还是,unix运行?是在哪一行oom的?

lyfree
lyfree
在win上
李国刚
李国刚
System.gc(),也是不确定的,而且还可以禁止显示调用.
0
Altman
Altman
jvm不是用的引用计数法,而且System.GC()好像只是标记,什么时候真正GC好像还是jvm说了算,我也忘了,不知道对不对
0
星爷
星爷
你的代码里就有对象的相互引用,就跟内存泄漏一样,没法gc掉,所以引用一直会存在,new第三个的时候,系统内存最大值已经设定,又无法执行gc,所以才会出错的。关于垃圾可以看下jvm的书,gc是按几个年代来回收的,采用的算法也不一样的
0
SHELBY
SHELBY
应该是引用计数,应该不是那个啥挂在树上的。
SHELBY
SHELBY
具体叫啥名忘了
0
Monkey
Monkey

java内存特征:

别指望在java程序里精确控制内存回收,既不能达到目标,而且往往事与愿违,当你越是想通过gc解决问题是反而制造问题。当gc不存在是最好的策略。

java使用内存杜绝一次申请大量内存,尤其是数组。实际上你的代码在第个test创建就已经挂了,你有10M,但是一个两个4M的数组足够造成内存泄漏。


0
huan
huan

还是好好看看jvm基础吧,你以为引用计数就是只要有个引用就不能回收?


0
lyfree
lyfree

引用来自“李国刚”的答案

java gc不是引用计数, 是根搜索法确定是否可以回收!

第二System.gc()有没有都没有关系,java会在 heap不够分配的时候触发gc。

第三,理论这不会oom,因为java是能够回收t1,t2。我在 win java version "1.6.0_07"
Java(TM) SE Runtime Environment (build 1.6.0_07-b06)
Java HotSpot(TM) Client VM (build 10.0-b23, mixed mode, sharing)

运行也确实没有oom。去掉t1=t2=null,会heap oom 

第四,java不是 你new byte[4 * 1024 * 1024]这么大,就是占用这么多内存,实际会比这个大,因为还有object header,object的一些占用,字节对齐等!

下午回来在测试下你说的,你是在win上运行还是,unix运行?是在哪一行oom的?

那就很奇怪了,我的用的比你的新,你都没OOM怎么我的就OOM了,而且我还测试了一下,只有用java -Xms13M -Xmx13M Test才不会OOM,下面是我的运行信息:
D:\Eclipse\testgc>java -Xms10M -Xmx10M Test
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
        at Test.<init>(Test.java:10)
        at Test.main(Test.java:20)


D:\Eclipse\testgc>java -version
java version "1.7.0_10"
Java(TM) SE Runtime Environment (build 1.7.0_10-b18)
Java HotSpot(TM) Client VM (build 23.6-b04, mixed mode, sharing)


D:\Eclipse\testgc>java -Xms13M -Xmx13M Test
Test@1afae45


D:\Eclipse\testgc>
0
13123123
13123123
 CG 回收 法则第一点是  null 并且 长时间不使用的时候会回收 第二点new 对象 已经好长时间没时间 那也会回收
0
excepiton
excepiton

java -Xms10m -Xmx10m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=oom.hprof Test

加个参数启动分析下dump文件


其实,你-Xms10m -Xmx10,考虑的只是堆内存,没考虑JVM的分代机制

返回顶部
顶部