Sun公司的HotSpot虚拟机,将内存管理划分为:线程独享和线程共享的两块区域
线程共享:比如我们new创建一个对象,对象在多线程中运行肯定是共享的 ===> 堆内存
线程独享:比如当前线程执行A方法,方法里面定义的局部变量,肯定是当前线程独享的 ===> 栈内存
这里描述的两块区域,就是一次粗糙的内存管理,也就是我们经常听到的:堆内存和栈内存
(1)Java堆:这是JVM内存管理中最大且最重要的一个区域,它存放着所有实例对象
从对象存活周期角度来看,可以看做是 新生代 和老年代
从内存分配角度来看,又可以更加细致的分为:Eden空间、From Survivor 空间 以及 To Survivor 空间
Java堆通过 -Xms 分配最小内存, -Xmx 分配最大内存,如果 -Xms = -Xmx ,则意味着堆内存不可扩展
(2)方法区:这里存放着静态变量、常量、类加载信息、类编辑后产生的字节码等信息
方法区又称之为 永久代,JVM对方法区的内存回收不尽如人意
它通过 -Xx:PermSize 分配方法区内存,-Xx:PermMaxSize 分配最大方法区内存
(3)Java虚拟机栈:它描述了Java方法内存模型,这里存放着方法局部变量、操作数、方法出口等信息
其实每执行一个Java方法,都是一个 栈桢(Stack Frame)进栈和出栈的过程
而所谓的 栈桢,就是存放着上面所说的:局部变量、操作数和方法出口等信息,它通过 -Xss 来分配内存
(4)Native本地方法栈:HotSpot虚拟机将它与Java虚拟机栈 合二为一
如果你通过 -Xoss 来分配本地方法栈内存,其实是无效的
(5)程序计数器PCR:存储当前线程正在执行的字节码的指令,占用内存非常小,不是内存回收的重点
通过改变PCR的值,其实就是通过改变指令所在的行号,获取下一条要执行的语句
比如if分支、for循环等等,每一条指令的执行,都是靠改变PCR的值来获取
通过以上描述,应该可以猜测得出来,哪些是线程共享的内存,哪些是独享内存
(1)和 (2) 也就是 Java堆和方法区是线程共享内存区域:这是内存回收的重点区域,特别是堆内存
(3)(4)(5)则是线程独享内存区域:所谓独享,也就是这里的内存区域生命周期和当前线程相同
这片内存随着线程的产生和而产生,随着线程的消亡而消亡,所以这里的内存也不是JVM内存回收的重点
Java堆内存溢出:堆是存放实例对象的区域,你用一个死循环不停创建对象,就可以模拟堆内存溢出
方法区内存溢出:这里存放着类的字节码信息,用个循环不停的动态产生类,比如使用cglib来创建
Java虚拟机栈内存溢出:这个更加单,你搞个递归调用,永不退出,运行到一定程度,一定会栈溢出的
这里模拟Java堆内存溢出,分配 -Xms20M -Xmx20M -Xmn10M
即最小和最大堆内存都是20M,用个循环来不停new对象,模拟内存溢出
我使用的是Spring的STS开发工具,和Eclipse差不多,可以在Debug Configurations面板配置
package t02;
import java.util.ArrayList;
import java.util.List;
/**
*
* -Xms20M -Xmx20M -Xmn10M
* 即指定初始最小最大堆内存均为10M,年轻代内存为10M
*
* @author yli
*
*/
public class Test {
public static void main(String[] args) {
List list = new ArrayList();
while (true) {
list.add(new Test());
}
}
}
那么运行结果,很显然会在控制台打印:java.lang.OutOfMemoryError: Java heap space
[GC [PSYoungGen: 7376K->1249K(8960K)] 7376K->5193K(19200K), 0.0077676 secs] [Times: user=0.01 sys=0.00, real=0.01 secs]
[GC [PSYoungGen: 8929K->1272K(8960K)] 12873K->10254K(19200K), 0.0104870 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[Full GC [PSYoungGen: 1272K->0K(8960K)] [ParOldGen: 8982K->10191K(10240K)] 10254K->10191K(19200K) [PSPermGen: 2647K->2645K(21248K)], 0.2981581 secs] [Times: user=0.39 sys=0.00, real=0.30 secs]
[Full GC [PSYoungGen: 7680K->6835K(8960K)] [ParOldGen: 10191K->8925K(10240K)] 17871K->15760K(19200K) [PSPermGen: 2645K->2645K(21248K)], 0.0964579 secs] [Times: user=0.20 sys=0.00, real=0.09 secs]
[Full GC [PSYoungGen: 7438K->7376K(8960K)] [ParOldGen: 8925K->8925K(10240K)] 16363K->16301K(19200K) [PSPermGen: 2645K->2645K(21248K)], 0.0901484 secs] [Times: user=0.14 sys=0.00, real=0.09 secs]
[Full GC [PSYoungGen: 7376K->7376K(8960K)] [ParOldGen: 8925K->8910K(10240K)] 16301K->16287K(19200K) [PSPermGen: 2645K->2645K(21248K)], 0.1168719 secs] [Times: user=0.16 sys=0.00, real=0.11 secs]
Exception in thread "main" Heap
PSYoungGen total 8960K, used 7599K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)
eden space 7680K, 98% used [0x00000000ff600000,0x00000000ffd6bed8,0x00000000ffd80000)
from space 1280K, 0% used [0x00000000ffec0000,0x00000000ffec0000,0x0000000100000000)
to space 1280K, 0% used [0x00000000ffd80000,0x00000000ffd80000,0x00000000ffec0000)
ParOldGen total 10240K, used 8910K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000)
object space 10240K, 87% used [0x00000000fec00000,0x00000000ff4b3b48,0x00000000ff600000)
PSPermGen total 21248K, used 2678K [0x00000000f9a00000, 0x00000000faec0000, 0x00000000fec00000)
object space 21248K, 12% used [0x00000000f9a00000,0x00000000f9c9da80,0x00000000faec0000)
java.lang.OutOfMemoryError: Java heap space
at java.util.Arrays.copyOf(Arrays.java:2245)
at java.util.Arrays.copyOf(Arrays.java:2219)
at java.util.ArrayList.grow(ArrayList.java:213)
at java.util.ArrayList.ensureCapacityInternal(ArrayList.java:187)
at java.util.ArrayList.add(ArrayList.java:411)
at t02.Test.main(Test.java:19)