有关JVM的GC问题
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);
}
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),求解释哦!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(13)
CG 回收 法则第一点是 null 并且 长时间不使用的时候会回收 第二点new 对象 已经好长时间没时间 那也会回收
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的?
还是好好看看jvm基础吧,你以为引用计数就是只要有个引用就不能回收?
java内存特征:
别指望在java程序里精确控制内存回收,既不能达到目标,而且往往事与愿违,当你越是想通过gc解决问题是反而制造问题。当gc不存在是最好的策略。
java使用内存杜绝一次申请大量内存,尤其是数组。实际上你的代码在第个test创建就已经挂了,你有10M,但是一个两个4M的数组足够造成内存泄漏。
具体叫啥名忘了
应该是引用计数,应该不是那个啥挂在树上的。
你的代码里就有对象的相互引用,就跟内存泄漏一样,没法gc掉,所以引用一直会存在,new第三个的时候,系统内存最大值已经设定,又无法执行gc,所以才会出错的。关于垃圾可以看下jvm的书,gc是按几个年代来回收的,采用的算法也不一样的
jvm不是用的引用计数法,而且System.GC()好像只是标记,什么时候真正GC好像还是jvm说了算,我也忘了,不知道对不对
System.gc(),也是不确定的,而且还可以禁止显示调用.
在win上
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的?
nice work!用 dump oom error是一种好的分析方法,也可以,用jstat,debug分析,看old和new的使用情况!当然还可以用其他分享工具!
以下是运行的时候堆分析
可以看出Old Gen 只有7M,你t2 new的时候内存已经不足了。