"Write Once,Run Anywhere"(一次编译,处处运行)是sun宣传Java语言所提出的口号。Java语言跨平台的特性与Java虚拟机的存在密不可分。Java源代码经过编译生成.class文件字节码后再被JVM解释转化为目标机器代码,处处运行的关键与前提就是JVM。因此并非Java语言自己能够能够跨平台,而是在不一样的平台都有可让Java语言运行的环境而已。在能够运行Java虚拟机的地方都内含一个JVM操做系统,从而使JAVA提供了各类不一样平台上的虚拟机制,因而可知导出运行的关键就是JVM。java
JVM结构数据结构
不断建立对象oracle
/**
* VM Args:-Xmx10m
*/
public static void main(String[] args) {
List list = new ArrayList();
while (true){
list.add(new Object());
}
}
复制代码
结果:
java.lang.OutOfMemoryError: Java heap space
ide
递归调用布局
private void test(){
test();
}
public static void main(String[] args) {
new StackTest().test();
}
复制代码
结果:
java.lang.StackOverflowError
优化
/**
* VM Args:-Xss2M
* @author zzm
*/
public class JavaVMStackOOM {
private void dontStop(){
while (true){
}
}
public void stackLeakByThread(){
while(true){
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
dontStop();
}
});
thread.start();
}
}
public static void main(String[] args) {
JavaVMStackOOM oom = new JavaVMStackOOM();
oom.stackLeakByThread();
}
}
复制代码
本人运行了一下果真像书(深刻理解Java虚拟机)中所说电脑重启了,Windows系统的同窗谨慎运行spa
/**
* VM Args:-XX:MetaspaceSize=10M -XX:MaxMetaspaceSize=10M (jdk8)
* -XX:PermSize=10M -XX:MaxPermSize=10M(jdk7)
* @author zzm
*/
public class Test {
static class OOMOjbect{}
public static void main(String[] args) {
while(true){
Enhancer eh = new Enhancer();
eh.setSuperclass(OOMOjbect.class);
eh.setUseCache(false);
eh.setCallback(new MethodInterceptor(){
@Override
public Object intercept(Object arg0, Method arg1,
Object[] arg2, MethodProxy arg3) throws Throwable {
return arg3.invokeSuper(arg0, arg2);
}
});
eh.create();
}
}
}
复制代码
本人用的是jdk8,输出结果:
java.lang.OutOfMemoryError: Metaspace操作系统
对象在内存中布局能够分红三块区域:对象头、实例数据和对齐填充
线程
对象头包括两部分信息:
设计
存储内容 | 标志位 | 状态 |
对象哈希码、对象分代年龄 | 01 | 未锁定 |
指向锁记录的指针 | 00 | 轻量级锁定 |
指向重量级锁的指针 | 10 | 膨胀(重量级锁定) |
空,不须要记录信息 | 11 | GC标记 |
偏向线程ID、偏向时间戳、对象分代年龄 | 01 | 可偏向 |
实例数据就是在程序代码中所定义的各类类型的字段,包括从父类继承的,这部分的存储顺序会受到虚拟机分配策略参数和字段在源码中定义顺序的影响
并非必然存在的,没有特别的含义。因为HotSpot的自动内存管理要求对象的起始地址必须是8字节的整数倍,即对象的大小必须是8字节的整数倍,对象头的数据正好是8的整数倍,因此当实例数据不够8字节整数倍时,须要经过对齐填充进行补全。
使用句柄访问的话,Java堆中将会划分出一块内存来做为句柄池,reference中存储的就是对象的句柄地址,而句柄中包含了对象实例数据与类型数据各自的具体地址信息:
使用直接指针访问的话,Java堆对象的布局中就必须考虑如何放置访问类型数据的相关信息,reference中存储的直接就是对象地址
这两种对象访问方式各有优点:
oracle JDK官方默认虚拟机HotSpot采用第二中方式进行对象访问
《极客时间——杨晓峰Java核心技术36讲第一讲》 《深刻理解Java虚拟机》