java开发过程中经常见到一堆有关内存的错误,比如:

Exception in thread “main”: java.lang.OutOfMemoryError: Java heap space

Exception in thread “main”: java.lang.OutOfMemoryError: PermGen space

我们统一叫做内存溢出,那么这些异常的底层到底有什么不同,各自属于JVM运行时的哪块区域?该怎么解决呢?想要彻彻底底的弄清楚这些疑惑,了解JVM内存结构就会随之而来。

JVM内存概念

首先,Java源代码文件(.java后缀)会被Java编译器编译为字节码文件(.class后缀),然后由JVM中的类加载器加载各个类的字节码文件,加载完毕之后,交由JVM执行引擎执行也就是常说的java项目运行过程。在整个程序执行过程中,JVM会用一段空间来存储程序执行期间需要用到的数据和相关信息,这段空间一般被称作为Runtime Data Area(运行时数据区),也就是我们今天分析的JVM内存。

在知道了JVM内存是什么东西之后,下面我们就开始分析它的组成。

JVM内存组成

JVM内存由程序计数器(Program Counter Register)、Java栈(JVM Stack)、本地方法栈(Native Method Stack)、方法区(Method Area)、堆(Heap)组成。

281726404166686.jpg

如上图所示,下面我们逐个分析。

堆-Heap

Java堆(Java Heap)是Java虚拟机所管理的内存中最大的一块。此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例都在这里分配内存。内存分配主要是由程序员显示的使用new关键字来触发的,至于new出来的这部分内存在哪分配,如何分配,则是JAVA虚拟机来决定。而这部分内存的释放,则是由自动内存管理系统(以下简称GC)来管理的。Java堆是被所有线程共享的一块内存区域,在虚拟机启动时创建。

Java堆是垃圾收集器管理的主要区域,因此很多时候也被称做“GC堆”。如果从内存回收的角度看,由于现在收集器基本都是采用的分代收集算法,所以Java堆中还可以细分为:新生代和老年代;再细致一点的有Eden空间、From Survivor空间、To Survivor空间等。根据Java虚拟机规范的规定,Java堆可以处于物理上不连续的内存空间中,只要逻辑上是连续的即可,就像我们的磁盘空间一样。在实现时,既可以实现成固定大小的,也可以是可扩展的,不过当前主流的虚拟机都是按照可扩展来实现的(通过-Xmx和-Xms控制)。如果在堆中没有内存完成实例分配,并且堆也无法再扩展时,将会抛出OutOfMemoryError异常。

方法区-Method Area

方法区(Method Area)与Java堆一样,是各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。虽然Java虚拟机规范把方法区描述为堆的一个逻辑部分,但是它却有一个别名叫做Non-Heap(非堆),目的应该是与Java堆区分开来。

我们知道堆中存储的是程序员new出来的对象实例,那么方法区存储的是什么?

1.方法区包含所有的class和static变量和常量。

2.方法区中包含类的信息,比如各种方法等。

举个例子:

public class HelloWorld {

private static Logger LOGGER = Logger.getLogger(HelloWorld.class.getName());

public void sayHello(String message) {

SimpleDateFormat formatter = new SimpleDateFormat("dd.MM.YYYY");

String today = formatter.format(new Date());

LOGGER.info(today + ": " + message);

}

}

上述代码运行内存分配如下

JUtH_20121024_RuntimeDataAreas_4_MemoryModel.png

对于习惯在HotSpot虚拟机上开发和部署程序的开发者来说,很多人愿意把方法区称为“永久代”(Permanent Generation),Java虚拟机规范对这个区域的限制非常宽松,相对而言,垃圾收集行为在这个区域是比较少出现的,但并非数据进入了方法区就如永久代的名字一样“永久”存在了。这个区域的内存回收目标主要是针对常量池的回收和对类型的卸载,一般来说这个区域的回收“成绩”比较难以令人满意,尤其是类型的卸载,条件相当苛刻,但是这部分区域的回收确实是有必要的。根据Java虚拟机规范的规定,当方法区无法满足内存分配需求时,将抛出OutOfMemoryError异常。

Java栈(JVM Stack)

Java虚拟机栈(Java Virtual Machine Stacks)是线程私有的,它的生命周期与线程相同。

虚拟机栈描述的是Java方法执行的内存模型:每个方法被执行的时候都会同时创建一个栈帧(Stack Frame)用于存储局部变量表、操作栈、动态链接、方法出口等信息。每一个方法被调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。

栈帧:简单点说,可以解释为是一个方法运行时,临时数据的存储区域,具体点说,它里面包括了数据和部分的过程结果,与此同时,它又肩负着处理方法返回值、动态链接以及异常分派的任务。栈帧是随着方法的创建而创建,随着方法的结束而销毁,如果方法抛出异常,也算方法结束。然而在每一个栈帧中,都有着自己的局部变量表以及操作数栈以及对当前类的运行时常量池的引用。

局部变量表:它是一个方法局部变量的列表,是在编译时期就写入了class文件当中。简单的理解,可以将它理解为一个对象数组,而里面按照索引0到length-1分别对应于每一个局部变量,特别的,如果是实例方法的局部变量表,第0个局部变量会是一个指向当前实例的引用,也就是this关键字,其余的局部变量则从索引1开始。

操作数栈:它是一个后进先出(LIFO)栈,而它的长度也是在编译时期就写入了class文件当中,是固定的。它的作用就是提供字节码指令操作变量计算的空间,比如简单的,对于int a=9这句话来说,就需要先将9压入操作数栈,再将9赋给a这个变量。

在Java虚拟机规范中,对这个区域规定了两种异常状况:如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowError异常;如果虚拟机栈可以动态扩展(当前大部分的Java虚拟机都可动态扩展,只不过Java虚拟机规范中也允许固定长度的虚拟机栈),当扩展时无法申请到足够的内存时会抛出OutOfMemoryError异常。

本地方法栈(Native Method Stack)

本地方法栈(Native Method Stacks)与虚拟机栈所发挥的作用是非常相似的,其区别不过是虚拟机栈为虚拟机执行Java方法(也就是字节码)服务,而本地方法栈则是为虚拟机使用到的Native方法服务。

native方法称为本地方法。在java源程序中以关键字“native”声明,不提供函数体。

其实现使用C/C++语言在另外的文件中编写,编写的规则遵循Java本地接口的规范(简称JNI)。

简而言就是Java中声明的可调用的使用C/C++实现的方法。

虚拟机规范中对本地方法栈中的方法使用的语言、使用方式与数据结构并没有强制规定,因此具体的虚拟机可以自由实现它。甚至有的虚拟机(譬如Sun HotSpot虚拟机)直接就把本地方法栈和虚拟机栈合二为一。与虚拟机栈一样,本地方法栈区域也会抛出StackOverflowError和OutOfMemoryError异常。

控制参数

最后通过一张图来了解如何通过参数来控制各区域的内存大小

jvm04.png

-Xms设置java堆的最小空间

-Xmx设置java堆的最大空间

-XX:NewSize设置新生代最小空间

-XX:MaxNewSize设置新生代最大空间

-XX:PermSize设置永久代(方法区)最小空间

-XX:MaxPermSize设置永久代(方法区)最大空间

-Xss设置每个线程的堆栈大小

老年代(Old Generation)大小:java堆大小-年轻代空间大小

本文中的JVM有关问题,欢迎沟通交流哦。

java内存结构不包含堆,JVM之详细分析java内存结构模型相关推荐

  1. JVM最详细知识点笔记-内存与垃圾回收篇

    内存与垃圾回收 一.JVM与JAVA体系结构 1.1 概述 JAVA虚拟机: 含义: Java虚拟机是一台执行Java字节码的虚拟计算机,它拥有独立的运行机制,其运行的Java字节码也未必由Java语 ...

  2. java lam表达式_详细分析Java Lambda表达式

    在了解Lambda表达式之前我们先来区分一下面向对象的思想和函数式编程思想的区别 面向对象的思想: 做一件事情,找一个能解决这个事情的对象,调用他的方法来解决 函数时编程思想: 只要能获取到结果,谁去 ...

  3. Java架构学习(十二)java内存结构新生代老年代JVM参数调优堆内存参数配置解决堆栈溢出

    JVM参数调优与垃圾回收机制 一.java内存结构 Java内存模型:是多线程里面的,jmm与线程可见性有关 Java内存结构:是JVM虚拟机存储空间. Java内存结构图 Java内存机构分为:方法 ...

  4. jvm内存结构_浅谈JVM内存结构

    JVM 可以分为 5 个部分,分别是: 类加载器(Class Loader):加载字节码文件到内存. 运行时数据区(Runtime Data Area):JVM 核心内存空间结构模型. 执行引擎(Ex ...

  5. java 内存跟踪_详解JVM中的本机内存跟踪

    1.概述 有没有想过为什么Java应用程序通过众所周知的-Xms和-Xmx调优标志消耗的内存比指定数量多得多?出于各种原因和可能的优化,JVM可以分配额外的本机内存.这些额外的分配最终会使消耗的内存超 ...

  6. java float内存结构_Java后端开发岗必备技能:Java并发中的内存模型

    欢迎关注专栏: Java架构技术进阶 .里面有大量batj面试题集锦,还有各种技术分享,如有好文章也欢迎投稿哦. JMM通过构建一个统一的内存模型来屏蔽掉不同硬件平台和不同操作系统之间的差异,让Jav ...

  7. JVM源码分析-Java运行

    最近在看Java并发编程实践和Inside JVM两本书,发现如果不真正的了解底层运作,那么永远是雾里看花.因此从http://openjdk.java.net/groups/hotspot/上下载了 ...

  8. Java 性能优化实战记录(3)--JVM OOM的分析和原因追查

    前言: C/C++的程序员渴望Java的自由, Java程序员期许C/C++的约束. 其实那里都是围城, 外面的人想进来, 里面的人想出去. 背景: 作为Java程序员, 除了享受垃圾回收机制带来的便 ...

  9. oracle有哪两种内存结构,Oracle体系结构详解(物理构造,内存结构和逻辑结构)...

    当前位置:我的异常网» 数据库 » Oracle体系结构详解(物理构造,内存结构和逻辑结构 Oracle体系结构详解(物理构造,内存结构和逻辑结构) www.myexceptions.net  网友分 ...

  10. 2022年各大企业java面试题解析,堪称全网最详细的java面试指南

    前言 最近感慨面试难的人越来越多了,一方面是市场环境,更重要的一方面是企业对Java的人才要求越来越高了. ​基本上这样感慨的分为两类人,第一,虽然挂着3.5年经验,但肚子里货少,也没啥拿得出手的项目 ...

最新文章

  1. 改变完成工作的方式压力的效果
  2. mybatis查询如何返回ListMap类型数据
  3. 【selenium2】【unittest】
  4. php mysql 查询每隔一段时间插入的数据_SQL查询某个时间段共多少条数据
  5. springSecurity源码分析-spring-security.xml文件配置
  6. 关 于 解 析 php 的 问 题
  7. RHEL5下DNS配置详解3
  8. vue怎么让接口带上cookie_在Vue中怎么使用cookie 之 vue-cookies
  9. 软件测试中开发团队和测试团队的职责
  10. STM32 - 定时器的设定 - 基础- 0D - Timer synchronization chaining - 主从模式下 - 定时器同步和级联控制 - 级联启动定时器
  11. topic1:Qt入门之搭建环境与hello world看Qt开发框架
  12. Unity编辑器汉化教程
  13. 收藏!一文掌握数据分析知识体系
  14. linux如何开启root权限控制,Linux下的Root权限控制
  15. 利用云片网提供的API发送短信
  16. SQL语言_2 DQL 数据查询基础
  17. 初识python之概念认知篇
  18. 总结:python代码实现矩阵最基本操作
  19. 双色球号码生成和验证
  20. matlab并联lc谐振电路图,串联谐振和并联谐振LC电路操作

热门文章

  1. 【裂缝识别】基于matlab无人机图像处理公路裂缝检测研究与实现【含Matlab源码 1730期】
  2. 【图像去雾】基于matlab GUI直方图均衡化+Retinex理论图像去雾【含Matlab源码 1509期】
  3. 【语音隐写】基于matlab LSB语音隐藏【含Matlab源码 431期】
  4. win7系统怎么用计算机,win7电脑配置怎么查看_win7系统查看电脑配置的方法
  5. 可视化排班管理_呼叫中心外包之管理要点与数据分析对策
  6. Twow ndows,笔者教您syswow64 【设置步骤】 的详细方法_
  7. mysql 1500万_【IT专家】mysql分表后 如何分页 (总共160个表1500万数据)
  8. .net函数查询_SQL窗口函数
  9. python基础:集合(set)
  10. 第 4 章 容器 - 030 - 实现容器的底层技术