1:JVM中的内存结构
1:JVM的区域
JVM中的内存主要划分为5个区域,即方法区,堆内存,程序计数器,虚拟机栈以及本地方法栈。下边是Java虚拟机运行时(runtime)数据区示意图
2:数据存储
下图是基于hotspot的jvm数据存储(不同虚拟机会有差异)
虚拟机栈、本地方法栈、程序计数器的三个区域是线程私有。
通常我们定义一个基本数据类型的变量,一个对象的引用,还有就是函数调用的现场保存都使用JVM中的栈空间
而通过new关键字和构造器创建的对象则放在堆空间,堆是垃圾收集器管理的主要区域,由于现在的垃圾收集器都采用分代收集算法,所以堆空间还可以细分为新生代和老生代,再具体一点可以分为Eden、Survivor(又可分为From Survivor和To Survivor)
方法区和堆都是各个线程共享的内存区域,用于存储已经被JVM加载的类信息、常量、静态变量、JIT(just in time)编译器编译后的代码等数据
程序中字面量,如100、”hello”和常量都是放在常量池中,常量池是方法区的一部分。
栈空间操作起来最快但是栈很小,通常大量的对象都是放在堆空间,栈和堆的大小都可以通过JVM的启动参数来进行调整,栈空间用光了会引发StackOverflowError,而堆和常量池空间不足则会引发OutOfMemoryError。
3:结论
栈是一种数据结构(FILO),作用是配合执行程序,提供执行程序必须的内存空间。栈存储程序执行时的临时数据
每个线程有自己的栈和程序指针(线程是程序执行的最小单位)
堆不是一种数据结构(什么结构都可以存放在堆中,数据,hash,列表)
应用通过堆存储数据(申请、回收、托管)
2:Java对象不都是分配在堆上
逃逸是指在某个方法之内创建的对象除了在方法体之内被引用之外,还在方法体之外被其它变量引用到。这样带来的后果是在该方法执行完毕之后,该方法中创建的对象将无法被GC回收。由于其被其它变量引用无法回收,即称为逃逸。
逃逸分析技术可以分析出某个对象是否永远只在某个方法、线程的范围内,并没有“逃逸”出这个范围,逃逸分析的一个结果就是对于某些未逃逸对象可以直接在栈上分配提高对象分配回收效率,对象占用的空间会随栈帧的出栈而销毁。