概述

Java语言的一个非常重要的特点就是与平台的无关性。而使用Java虚拟机是实现这一特点的关键。一般的高级语言如果要在不同的平台上运行,至少需要编译成不同的目标代码。而引入Java语言虚拟机后,Java语言在不同平台上运行时不需要重新编译。Java语言使用Java虚拟机屏蔽了与具体平台相关的信息,使得Java语言编译程序只需生成在Java虚拟机上运行的目标代码(字节码),就可以在多种平台上不加修改地运行。Java虚拟机在执行字节码时,把字节码解释成具体平台上的机器指令执行。这就是Java的能够“一次编译,到处运行”的原因。

一、运行时数据区域

在java程序执行的过程中,jvm会把它所管理的内存区域划分为不同的数据区域,因为在计算机中,操作系统是老大,操作系统分配一定的内存给到jvm,jvm就是一个小家庭,拿到了土地了,比如这块呢做房子,那块种菜园,后面一块做池塘。。这样每块地都互不干扰,也都有自己的用途。如图:

红框区域代表是所有线程共享的区域,绿色区域则非线程共享,每个线程都自己管理这些数据区域。

1、堆

大部分的java项目中,堆内存都是最大的,因为堆的唯一目的就是存放对象实例,包含所有的对象以及数组都存放在这里。但是随着JIT编译器的发展,这一点也不是那么绝对了,这点以后再介绍,当前可以认为所有对象都存放在堆内存中。

另外堆中内存还可以细分:Eden、From Survivor、To Survivor、Old Generation,前三者属于新生代,最后一个则是老年代。

2、栈

在java中,栈分为虚拟机栈以及本地方法栈。是java程序方法执行时的内存模型,当执行到一个方法时,栈中就会创建一个栈帧,如图所示:

本地方法栈与虚拟机栈的作用非常类似,只是虚拟机栈执行的是java方法,本地方法栈执行的是native方法。

3、程序计数器

是一块较小的内存区域,可以看做是当前线程所执行的字节码的行号指示器。字节码解释器就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器来完成。

4、方法区

用于存储已被虚拟机加载的类信息、常量(放入运行时常量池)、静态变量、即时编译器编译后的代码等数据。说到运行时常量池,string很有发言权,当声明String s = "虚拟机";首先自然是创建一个string对象放在堆中,另外会把"虚拟机"字符串放入到

运行时常量池,可以理解成缓存,不明白的可以看走进JDK(二)------String

另外值得一提的就是直接内存,这块内存不归jvm管理,但是在nio中使用到,可以使用native函数库直接分配堆外内存,然后通过一个存储在堆中的DirectByteBuffer对象作为这块内存的引用进行操作。拿nio来说,这种操作能够大大提高性能,因为避免了在java堆和native堆中来回复制数据。

二、对象创建过程

当我们new xxx()时,可曾想过背后到底发生了什么? 看图:

三、对象内存布局

对象在内存中存储的布局主要分为三块:对象头、实例数据和对齐补充。
对象头:
1、用于存储对象自身运行时数据,如哈希码、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等。
2、另一部分是类型指针,即对象指向它的类元数据的指针,迅疾通过这个指针来确定这个对象时哪个类的实例。
实例数据:对象真正存储的有效信息,也是在程序代码中所定义的各种类型的字段内容。父类继承下来的字段,也会在子类中存储。
对齐补充:仅仅起着占位符的作用。主要是因为jvm要求对象起始地址必须是8字节的整数倍,换句话说,就是对象的大小必须是8字节的整数倍,所以当实例数据部分没有对齐时,就需要通过对齐填充来补全。

四、对象的访问定位 

对象创建好了之后,如何使用对象呢?通过栈上的reference数据来操作堆上的具体对象,主流的访问方式有句柄和直接指针两种:

1、句柄

优点:当对象移动的时候(垃圾回收的时候移动很普遍),这样值需要改变句柄中的指针,但是栈中的指针不需要变化,因为栈中存储的是句柄的地址
缺点:需要进行二次定位,寻找两次指针,开销相对于更大一些

2、直接指针

优点:速度快,不需要和句柄一样指针定位的开销

对于sun hotspot虚拟机来说,使用的是第二种方式。

五、OutOfMemoryError与StackOverflowError

1、OutOfMemoryError:

各内存区域中,栈、堆、方法区、直接内存都有可能抛出此异常。

栈:当虚拟机栈可以动态扩展时,无法申请到足够的内存时,就会抛出此异常。

while(true) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
while(true) { }
}
});
thread.start();
}

堆:当堆中没有内存完成实例分配,并且堆也无法再扩展时,将会抛出此异常。

List list = new LinkedList();
while(true) {
list.add(student);
}

方法区:当方法区无法满足内存分配需求时,将抛出此异常。

2、StackOverflowError:

线程请求的栈深度大于虚拟机所允许的深度,将会抛出此异常。

这么说估计很多人都不明白,来个示例:

。。。main() {
method()
}
//method()不停的调用自己,此时就会出现StackOverflowError
void method() {
method()
}

深入理解java虚拟机(一)-----java内存区域以及内存溢出异常的更多相关文章

  1. 深入理解java虚拟机系列(一):java内存区域与内存溢出异常

    文章主要是阅读<深入理解java虚拟机:JVM高级特性与最佳实践>第二章:Java内存区域与内存溢出异常 的一些笔记以及概括. 好了開始.假设有什么错误或者遗漏,欢迎指出. 一.概述 先上 ...

  2. 深入理解Java虚拟机之Java内存区域与内存溢出异常

    Java内存区域与内存溢出异常 运行时数据区域 程序计数器 用于记录从内存执行的下一条指令的地址,线程私有的一小块内存,也是唯一不会报出OOM异常的区域 Java虚拟机栈 Java虚拟机栈(Java ...

  3. 深入理解Java虚拟机之图解Java内存区域与内存溢出异常

    Java内存区域与内存溢出异常 运行时数据区域 程序计数器 用于记录从内存执行的下一条指令的地址,线程私有的一小块内存,也是唯一不会报出OOM异常的区域 Java虚拟机栈 Java虚拟机栈(Java ...

  4. 深入理解Java虚拟机之Java内存区域随笔

    1.java内存区域与内存溢出异常 Java 虚拟机在执行 Java 程序的过程中会把它管理的内存划分成若干个不同的数据区域:1.程序计数器,2.栈(虚拟机栈和本地方法栈 ),3.堆,4.方法区(包含 ...

  5. 《深入理解java虚拟机》第二章 Java内存区域与内存溢出异常

    第二章 Java内存区域与内存溢出异常 2.2 运行时数据区域  

  6. 深入理解java虚拟机-第二章:java内存区域与内存泄露异常

    2.1概述: java将内存的管理(主要是回收工作),交由jvm管理,确实很省事,但是一点jvm因内存出现问题,排查起来将会很困难,为了能够成为独当一面的大牛呢,自然要了解vm是怎么去使用内存的. 2 ...

  7. 深入理解Java虚拟机(1)--Java内存区域

    运行时数据区域 Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域.这些区域有各自的用途,以及创建和销毁的时间,有的区域随着虚拟机进程的启动而存在,有些区域则是依赖用 ...

  8. 深入理解java虚拟机---->java内存区域与内存溢出异常

    2. java内存区域于内存溢出异常 2.1 概述: 对于C/C++而言,内存管理具有最高的权利,既拥有每一个对象的“所有权”,又担负着每一个对象生命开始到结束的维护责任. 对于java而言,则把内存 ...

  9. 《深入理解Java虚拟机》之(一、内存区域)

    一.java的体系构成: Java的技术体系主要由支撑java程序运行的虚拟机.提供各种开发领域接口支持的java api.java编程语言及许多第三方java框架(如Spring .Struts等) ...

  10. 深入了解Java虚拟机(1)java内存区域与内存溢出异常

    java内存区域与内存溢出异常 一.运行时数据区域 1.程序计数器:线程私有,用于存储当前所执行的指令位置 2.Java虚拟机栈:线程私有,描叙Java方法执行模型:执行方法时都会创建一个栈帧,存储局 ...

随机推荐

  1. 聊聊 HashMap

    数据存储底层? 数据底层具体存储是一个Node<K,V> HashMap 是基于哈希来映射的,那当映射冲突时候怎么解决? 链地址,数组+链表 HashMap 什么时候扩容? 负载因子 lo ...

  2. 吴裕雄 python深度学习与实践(18)

    # coding: utf-8 import time import numpy as np import tensorflow as tf import _pickle as pickle impo ...

  3. hadoop启动报错:localhost: ssh: Could not resolve hostname localhost

    hadoop启动journalnode时报错:localhost: ssh: Could not resolve hostname localhost: Temporary failure in na ...

  4. CSS 布局术语

    这一节的知识非常重要,它关系到能否做出漂亮的网站.下面的概念.术语需要好好理解. 构建块:CSS采用盒子模型来处理每个HTML元素.盒子可以是一个“块级”盒子,也可以是一个“内联”盒子. 包含元素:包 ...

  5. Redhat系统上开启Telnet服务

    https://blog.csdn.net/wolfofsiberian/article/details/51635952 1.操作系统 Redhat Step1:修改配置文件/etc/xinetd. ...

  6. 布署配置管理中心apollo

    Apollo(阿波罗)是携程框架部门研发的分布式配置中心,能够集中化管理应用不同环境.不同集群的配置,配置修改后能够实时推送到应用端,并且具备规范的权限.流程治理等特性,适用于微服务配置管理场景. 服 ...

  7. python中reshape重组数据方式

    方法numpy.reshape()是怎么进行数据重新定义shape?先生成一个随机数组 reshape成5行3列,可以看到是把(5,3)中第一行的剩余两列数据作为第二行的前两列,以此类推 reshap ...

  8. 爬虫学习--MOOC爬取豆瓣top250

    scrapy框架 scrapy是一套基于Twisted的异步处理框架,是纯python实现的爬虫框架,用户只需要定制开发几个模块就可以轻松实现一个爬虫,用来抓取网页内容或者各种图片. scrapy E ...

  9. vue项目中使用less或者sass的方法

    半年木有更新博客了... 前段时间一直在学习vue,开始记录一下遇到的问题吧 这篇文章主要是总结一下vue中使用less或者sass的方法,以less为例(style.less) 主要是两种 1.对于 ...

  10. Windows学习"Network Analysis in Python"

    原代码仓库的地址为 Network Analysis in Python. 主要按照里面的README.md 进行操作,全部仓库有100MB以上.考虑到数据比较大,再加上我对原笔记文件有修改,建议从我 ...