Java虚拟机内存管理(一)

1.前言

Sun公司的HotSpot虚拟机,将内存管理划分为:线程独享和线程共享的两块区域

线程共享:比如我们new创建一个对象,对象在多线程中运行肯定是共享的 ===> 堆内存

线程独享:比如当前线程执行A方法,方法里面定义的局部变量,肯定是当前线程独享的 ===> 栈内存

这里描述的两块区域,就是一次粗糙的内存管理,也就是我们经常听到的:堆内存和栈内存

 

2.HotSpot虚拟机的内存划分

(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内存回收的重点

3.如何模拟每个区域的内存溢出

Java堆内存溢出:堆是存放实例对象的区域,你用一个死循环不停创建对象,就可以模拟堆内存溢出

方法区内存溢出:这里存放着类的字节码信息,用个循环不停的动态产生类,比如使用cglib来创建

Java虚拟机栈内存溢出:这个更加单,你搞个递归调用,永不退出,运行到一定程度,一定会栈溢出的

4.简单示例模拟内存溢出

这里模拟Java堆内存溢出,分配 -Xms20M -Xmx20M  -Xmn10M

即最小和最大堆内存都是20M,用个循环来不停new对象,模拟内存溢出

我使用的是Spring的STS开发工具,和Eclipse差不多,可以在Debug Configurations面板配置

Java虚拟机内存管理(一)_第1张图片

 

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)


 

你可能感兴趣的:(Java,虚拟机,java,jvm,内存管理)