我的困惑
最近做的一个项目涉及到数据量比较大,涉及一个约200G大的excel表格,是不可能在内存里打开的.我要做的事情其中一步是遍历整个大表,拿出其中一部分数据.我计算了一下我需要的内存大小,应该是在6-8G,再考虑到我机器的性能(16g内存),想想应该可以用一个hashmap来存我想要的数据.于是开心的写出了程序,用一个全局的hashmap变量来保存数据.结果每次是运行了差不多两个小时的时候程序就崩了,出现的错误当然是内存溢出:
java.lang.outofMemery:gc overhead limit exceeded
或者:
java.lang.outofMemery:Java heap space
我试了修改eclipse.ini文件,增加了jvm的内存分配:
-Xms1024m
-Xmx8192m
-XX:PermSize=512m
-XX:MaxPermSize=2048m
结果依然没有解决问题,有的同学说,eclipse.ini只是为jvm分配内存的.而你真正运行的这个java程序不一定就分配到了那么多的内存,因为可能你正在运行好几个java程序,他们要一起竞争jvm内存.如果想要为我的java程序单独分配内存,需要为它添加启动参数,具体是这么做的:
Run-->Run Configuration-->(x)=arguments
在VM arguments下输入
-Xms1024m
-Xmx8192m
以及其他你想要的参数,然后点击aplly.
如下图.
看到有人说可以用:
-XX:-UseGCOverheadLimit
来Disabling the error check altogether.但又出现:
java.lang.outofMemery:Java heap space
的错误.所以我想问题应该不仅仅是内存不够用那么简单,至少通过增加jvm内存的方式来解决似乎让人看不到尽头.于是我好好学习了一下java的GC机制,看到底是什么地方导致了内存溢出.
堆与栈:生存空间
- 堆(heap):对象的生存空间.
- 栈(stack):方法调用和局部变量.
- 实例变量 :被声明在类里面的变量,它代表某个独立对象的"字段",存在于所属的对象中.
- 局部变量 :声明在方法中,生命周期只限于方法被放在栈上的这段期间.也就是方法被调用到结束的时间.
注意到一个事实,对象永远存在于堆上,如果我们在方法中定义了一个类类型变量,并赋值给它一个对象,其实我们只是定义了该对象的一个引用,引用变量本身是放在栈上面的,它所引用的对象还是在堆里.
当你调用一个方法时,该方法会放在调用栈的栈顶,它带有方法的状态,包括执行到那一行程序以及所有的局部变量的值,如果在方法中又调用了其他的方法,那么被调用的方法又被推到了堆栈顶,直到执行完毕被释放,回到上一个方法.
构造函数的执行顺序
public class Animal{
public Animal(){
System.out.println("making an animal");}
}
public class Hippo extends Animal{
public Hippo(){
System.out.println("making a hippo");}
}
public class TestHippo{
public static void main()(String args[]){
System.out.println("making a hippo");
Hippo h = new Hippo();}
}
所有的java对象都有一个共同的祖先:Object类. 所以执行顺序是:
Object()
Animal() Animal() Animal()
Hippo() Hippo() Hippo() Hippo() Hippo()
调用Hippo()时,会调用父类的构造函数,依次上升,直到Object类,然后依次返回,直到Hippo类.
如何调用父类的构造函数
可以使用super()函数,注意super();必须是你的构造函数的第一行代码.如果你没有显示使用super函数,编译器会为你生成一个super,使用父类的无参数构造函数,当然你完全可以使用父类的带参数的构造函数,只要往super里传入相应类型的值就可以了.
public class Hippo extends Animal{
public Hippo(String name){
super(name);}
}
引用变量与对象
- 除非有对象的引用,否则该对象一点意义都没有.
- 如果你无法取得对象的引用,则此对象只是浪费空间罢了.
- 一旦对象无法取得,GC会知道该怎么做,那种对象迟早会葬送在垃圾手机器的手上.
有三种方法可以释放对象的引用:
- 引用永久性的离开它的作用域
void go(){
Life z = new Life();
}
z会在方法结束时消失.
- 引用被赋值到其他对象上
Life z = new Life();
z = new Life();
第一个对象会在z被赋值到别处时挂掉.
- 直接将引用设定为null
Life z = new Life();
z = null;
第一个对象会在z被设定为null时挂掉.
Comments !