JVM执行Java程序的过程中管理的内存空间,包括下列几个区域:
程序计数器(Program CounterRegister)
程序计数器(Program CounterRegister)
· 线程私有,占用空间很小。
· 线程所执行代码行号指示器。
· 解释器通过计数器的值选择下一条执行的字节码指令。
· 线程执行Native方法时值为空。
· 没有OOM(OutOfMemory)。Java虚拟机栈(Java Virtual Machine Stacks)
· 线程私有。· 储存方法栈帧(Stack Frame)。
· 栈帧:储存局部变量表、操作栈、动态链接、方法出口等。
· 局部变量表:编译器可知的基本类型、对象引用和returnAddress(字节码指令的地址)。在编译期间完成分配,运行时大小不变。
· 存在StackOverflowError和OOM。
· StackOverflowError:线程请求栈深度大于VM允许深度。
· OOM:创建线程或扩展线程空间时无足够内存。
StackOverflowError例子:
StackOverflowError例子:
/**
*
-
Xss256k
*
*
*/
public
class
StackSOF {
int
recursionLength
;
void
recusion() {
recursionLength
++;
recusion();
}
public
static
void
main(String[] args) {
StackSOF sof =
new
StackSOF();
try
{
sof.recusion();
}
catch
(Throwable e) {
System.
out
.println(sof.
recursionLength
);
e.printStackTrace();
}
}
}
OOM例子:
/**
*
-
Xss2m
*
*
*/
public
class
StackOOM {
static
class
Tester
extends
Thread {
@Override
public
void
run() {
try
{
Thread.sleep(1000 * 1000);
}
catch
(InterruptedException e) {
e.printStackTrace();
}
}
}
public
static
void
main(String[] args) {
for
(
int
i = 0;; i++) {
new
Tester().start();
System.
out
.println(i);
}
}
}
本地方法栈(Native MethodStacks)
· 线程私有,类似虚拟机栈。
· 服务Native方法。
· 同样存在StackOverflowError和OOM。
· Hotspot中将Java虚拟机栈和本地方法栈合二为一,通过-Xss设置大小。JDK1.6以前默认256K,1.6默认1M。
Java堆(Java Heap)
· 所有线程共享。
· 储存对象实例。
· GC和OOM的主要区域。
Heap OOM例子:
/**
*
-
Xms10m
-
Xmx10m
*
*
*/
public
class
HeapOOM {
public
static
void
main(String[] args) {
List<Long> list =
new
ArrayList<Long>();
for
(
long
i = 0;; i++) {
list.add(i);
System.
out
.println(i);
}
}
}
方法区(Method Area)
· 又叫非堆(Non-Heap),对应HotSpot的永久代(Permanent Generation)。
· 所有线程共享。
· 储存VM加载的类信息、常量、静态变量、JIT编译代码等。
· 也有OOM,一般是由于大量使用反射生成class。
· 包含运行时常量池(Rumtime ConstantPool)。
常量池溢出例子:
/**
*
-
XX:MaxPermSize=1m
*
*
*/
public
class
ConstantPoolOOM {
public
static
void
main(String[] args) {
List<String> list =
new
ArrayList<String>();
for
(
int
i = 0;; i++) {
list.add(String.valueOf(i).intern());
System.
out
.println(i);
}
}
}
本机直接内存(Direct Memory)
· 不受VM直接管理,但也有OOM。
· 和NIO中的DirectByteBuffer相关。
· 默认和Java堆大小一致。
例子:
/**
*
-
XX:MaxDirectMemorySize=10m
*
*
*/
@SuppressWarnings
(
"restriction"
)
public
class
DirectMemoryOOM {
static
final
int
_1MB
= 1024 * 1024;
static
void
unsafeAllocate()
throws
IllegalArgumentException,
IllegalAccessException {
Field unsafeField = Unsafe.
class
.getDeclaredFields()[0];
unsafeField.setAccessible(
true
);
Unsafe unsafe = (Unsafe) unsafeField.get(
null
);
List<Long> list =
new
ArrayList<Long>();
for
(
int
i = 0;; i++) {
long
l = unsafe.allocateMemory(
_1MB
);
list.add(l);
System.
out
.println(i);
}
}
static
void
byteBufferAllocate(
boolean
direct) {
List<ByteBuffer> list =
new
ArrayList<ByteBuffer>();
for
(
int
i = 0;; i++) {
ByteBuffer bb;
if
(direct) {
bb = ByteBuffer.allocateDirect(
_1MB
);
}
else
{
bb = ByteBuffer.allocate(
_1MB
);
}
list.add(bb);
System.
out
.println(i);
}
}
public
static
void
main(String[] args)
throws
IllegalArgumentException,
IllegalAccessException {
byteBufferAllocate(
true
);
// unsafeAllocate();
}
}
Hotspot Java内存空间结构
![](http://10.28.169.186/wordpress/wp-content/uploads/2013/03/1.jpg)
新生代(Young Generation)
![](http://10.28.169.186/wordpress/wp-content/uploads/2013/03/1.jpg)
新生代(Young Generation)
大部分的对象的内存分配和回收在这里完成。
Eden
新建的对象分配在此,minor GC后被清空。
Survivor
存储至少经过一次GC存活下来的对象,以增大该对象在提升至老生代前被回收的机会。
From Space
在minor GC后被清空,GC后存活的对象放入老生代。
To Space
Eden中在新生代GC后存活的对象放在此。
老生代(Old Generation)
多次GC后存活的对象或者新生代放置不下的大对象。
永生代(PermanentGeneration)
方法区。