今天学习内存溢出的问题 涉及到一个博客
http://blog.csdn.net/seelye/article/details/8269705
内的第二个例子验证有误,具体如下:
public class testset {
//这个测试可以看出其实是通过引用判断
public static void main(String[] args)
{
Set<Person> set = new HashSet<Person>();
Person p1 = new Person("唐僧","pwd1",25);
Person p2 = new Person("孙悟空","pwd2",26);
Person p3 = new Person("猪八戒","pwd3",27);
set.add(p1);
set.add(p2);
set.add(p3);
Person p4 = new Person("猪八戒","pwd3",27);
set.add(p4);
System.out.println("总共有:"+set.size()+" 个元素!"); //结果:总共有:4 个元素!
p3.setAge(2); //
set.remove(p3); //
System.out.println("总共有:"+set.size()+" 个元素!"); //结果:总共有:4 个元素!
set.add(p3); //重新添加,居然添加成功
System.out.println("总共有:"+set.size()+" 个元素!"); //结果:总共有:4 个元素!
for (Person person : set)
{
System.out.println(person.toString());
}
}
}
这里我推断key的保存原理是根据对于对象的引用
查看hashset源代码
public boolean add(Object obj)
{
return map.put(obj, PRESENT) == null;
}
public boolean remove(Object obj)
{
return map.remove(obj) == PRESENT;
}
这里present 为一个静态的object 用于存放每一个要操作的对象
所以remove方法前后随意改变对象的属性,只要引用不改变就每问题
如果创建一个新的对象和原来某个对象所有属性一样,此时remove返回false,证明引用
然后关于第一种说法的内存溢出
1、静态集合类引起内存泄露:
像HashMap、Vector等的使用最容易出现内存泄露,这些静态变量的生命周期和应用程序一致,他们所引用的所有的对象Object也不能被释放,因为他们也将一直被Vector等引用着。
测试如下:
public static void main(String[] args)
{
Map<Integer, Person> map=new HashMap<Integer, Person>();
for (int i = 0; i < 100000000; i++) {
Person p=new Person();
map.put(i, p);
p=null;
}
}
之后观察内存发现内存持续走高,验证成功
然后我想如果增加到某一个状态,让线程等待一下会不会调用gc来回收,于是做以下测试
public static void main(String[] args) throws InterruptedException
{
Map<Integer, Person> map=new HashMap<Integer, Person>();
for (int i = 0; i < 100000000; i++) {
Person p=new Person();
map.put(i, p);
p=null;
if (i==20000000) {
map=null;
break;
}
}
System.out.println("完毕");
map=null;
Thread.currentThread().sleep(50000);
}
发现等待的50s里面gc并没有回收这个map,于是继续做测试。
public static void main(String[] args) throws InterruptedException
{
Map<Integer, Person> map=new HashMap<Integer, Person>();
for (int i = 0; i < 100000000; i++) {
Person p=new Person();
map.put(i, p);
p=null;
if (i==20000000) {
map=null;
break;
}
}
System.out.println("完毕");
map=null;
Map<Integer, Person> map2=new HashMap<Integer, Person>();
for (int i = 0; i < 100000000; i++) {
Person p=new Person();
map2.put(i, p);
p=null;
if (i==20000000) {
map2=null;
break;
}
}
System.out.println("完毕");
}
第一个完成后内存7.7g,第二个完成后内存居然差不多也是8.多个g
把后面的20000000改成30000000.
此时得到了一个惊呆我的发现
我的电脑初始为5.7g,当达到7.7g时完成第一个循环,第二个循环开始后前大段时间居然内存没啥变多,也就多了100兆左右。后半段增加到8g多
然后我就有两个猜测,第一个是这么多个循环的时候,person对象是复用的
第二个猜测是gc是逐渐进行内存销毁的,于是我打开jvisualvm一探究竟
以为主线程sleep gc会停止 然后看了下下面的说法
http://bbs.csdn.net/topics/390219766 说明main sleep的时候并没有gc
public static void main(String[] args) throws InterruptedException
{
Map<Integer, Person> map=new HashMap<Integer, Person>();
for (int i = 0; i < 100000000; i++) {
Person p=new Person();
map.put(i, p);
p=null;
if (i==20000000) {
break;
}
}
System.out.println("完毕");
map=null;
System.gc();
Thread.currentThread().sleep(100000);
Map<Integer, Person> map2=new HashMap<Integer, Person>();
for (int i = 0; i < 100000000; i++) {
// Person p=new Person();
// map2.put(i, p);
// p=null;
// if (i==30000000) {
// break;
// }
}
System.out.println("完毕");}
改成这样,发现内存还是占用的,然后我想到了,会不会main就是jvm的线程导致他不会执行gc,这只是我的猜测。之后验证
然后进入了jvm学习阶段。。
http://www.cnblogs.com/qmfsun/p/5479231.html