JVM的内存分配主要基于两种,堆和栈。
我们来看一下java程序运行时候的内存分配策略:
1):静态存储区(方法区);
2):栈区;
3):堆区;
1):主要存放静态数据,全局static数据和常量。
2):在java中,栈的分配是和线程绑定在一起的,当我们创建一个线程的时候,很显然,JVM就会为这个线程创建一个java栈,一个线程的方法的调用和返回对应于这个java栈的压栈和出栈。当线程激活一个java方法时,JVM就会线程的java堆栈里新压入一个帧,这个帧自然成了当前帧。在此方法执行期间,这个帧用来保存参数,局部变量,中间计算过程和其他数据。
栈中主要存放一些基本类型的变量数据(int,short,long,byte,float,double,boolean,char)和对象的句柄(引用)。方法体内的局部变量都在栈上创建的。
优点:存取速度比堆快,仅次于寄存器,栈数据可以共享。
缺点:存在栈中的数据大小与生存期必须是确定的,因此缺乏灵活性。
3):每个java应用都唯一对应一个JVM实例,每个实例唯一对应一个堆。堆是一个运行时数据区。
堆中存放的是应用程序在运行中所创建的所有类实例或数组,并由应用程序的所有线程贡献。这些对象通过new,newarray,anewarray和multianewarray等指令建立。
优点:堆由垃圾回收来负责,可以动态的分配内存大小,生存期也不必实现告诉编译器,因为它是在运行时动态分配内存的,java的垃圾收集器会自动收走这些不再使用的数据。
缺点:由于要在运行时动态分配内存,存取速度较慢。
在java中分配堆内存是自动初始化的,所有对象的存储空间都是在堆中分配的,但是这个对象的引用却是在堆栈中分配的。因此建立一个对象的时候两个地方都要分配内存,在堆中分配的内存实际建立这个对象,而在堆栈中分配的内存只是一个指向这个堆对象的指针(引用)而已。
接下来我们看一下java的垃圾回收机制。
当堆内存不再被任何引用变量引用的时候,这块内存就变成垃圾,等待垃圾回收机制进行回收。
java的垃圾回收机制的特点:
1、只负责回收堆内存的中的对象,不回收任何物理资源(如数据库的连接,网络IO等资源)。
2、程序无法精确地控制垃圾回收的运行,其会在合适的时候运行。当对象永久性地失去引用后,系统就会在合适的时候回收它所占用的内存。
3、在垃圾回收机制回收任何对象之前,总会先调用它的finalize()方法,该方法可能使该对象重新复活(让一个引用变量重新引用该对象),从而使垃圾回收机制取消回收。
堆内存中的对象可以分为三种状态:
1、可达状态:被一个以上的引用变量引用。
2、可恢复状态:没有引用变量引用它,系统的垃圾回收机制准备回收该对象占有的内存,在这之前系统会调用可恢复状态对象的finalize()方法进行资源清理,若是调用该方法时重新让一个引用变量引用该对 象,那么这个对象会再次变为可达状态,否则进入不可达状态。
3、不可达状态:当系统处于这种状态的时候,系统才会真正回收该对象所占有的资源。
程序是无法精确地控制垃圾回收何时进行,但是可以强制系统进行垃圾回收,这只是对系统的一种建议,系统是否进行垃圾回收是不确定的。垃圾回收也不会对程序的建议完全置之不理:垃圾回收机制会在收到通知后尽快进行垃圾回收。
强制垃圾回收有以下两种方式:
1、System.gc().
2、Runtime.getRuntime().gc().