点击上方的“ java full stack technology”,以每天学习和学习Java知识点
所有Java开发人员都可能遇到这样的困惑吗?我应该为堆内存设置多少空间? OutOfMemoryError异常涉及运行时数据的哪个区域?我该如何解决?实际上,如果您经常解决服务器性能问题,这些问题将变得非常普遍。了解JVM内存还可以在服务器出现性能问题时快速了解出现问题的内存区域,从而快速解决生产故障。
先看一张图,这张图可以清楚地说明JVM内存结构的布局。

JVM内存结构具有三个主要块:堆内存,方法区域和堆栈。堆内存是由年轻一代和老一代组成的最大的JVM块,并且年轻一代内存分为三个部分:Eden空间,From Survivor空间和To Survivor空间。默认情况下,年轻一代的分配比例为8:1:1;
方法区域存储数据,例如类信息,常量和静态变量。这是线程共享的区域。为了与Java堆区分开来,方法区域还具有别名Non-Heap(non-heap);堆栈分为Java虚拟机堆栈,本地方法堆栈主要用于方法执行。
通过图片了解如何通过参数控制每个区域的内存大小

控制参数
没有直接设置旧一代的参数,但是可以设置堆空间大小和年轻一代的空间大小这两个参数来间接控制。
上一代空间大小=堆空间大小-新一代大空间大小
再次从更高的角度查看JVM与系统调用之间的关系

方法区域和对是所有线程共享的内存区域;而Java堆栈,本地方法堆栈和程序员计数器是线程专用的内存区域。
下面我们详细介绍每个区域的作用
Java堆(堆)
对于大多数应用程序,Java堆是Java虚拟机管理的最大内存块。 Java堆是所有线程共享的内存区域,并在虚拟机启动时创建。该内存区域的唯一目的是存储对象实例,几乎所有对象实例都在此处分配内存。
Java堆是由垃圾收集器管理的主要区域,因此通常称为“ GC堆”。从内存回收的角度来看,由于当前的收集器基本上是使用世代收集算法,因此Java堆也可以细分为:新一代和旧代;更详细的信息包括Eden空间,From Survivor空间,To Survivor空间等等。
根据Java虚拟机规范,Java堆可以在物理上不连续的内存空间中,只要它在逻辑上是连续的(就像我们的磁盘空间一样)即可。在实现中,它可以实现为固定大小或可扩展,但是当前的主流虚拟机是根据可伸缩性(由-Xmx和-Xms控制)实现的。
如果堆中没有内存来完成实例分配,并且无法再扩展堆,则会抛出OutOfMemoryError异常。
方法区域
方法区,就像Java堆一样,是每个线程共享的内存区。它用于存储虚拟机已加载的数据,例如类信息,常量,静态变量和由即时编译器编译的代码。尽管Java虚拟机规范将方法区域描述为堆的逻辑部分,但它具有一个称为“非堆”(non-Heap)的别名,目的是将其与Java堆区分开。
对于习惯于在HotSpot虚拟机上开发和部署程序的开发人员,许愿意将其称为“永久生成”方法。从本质上讲,这两者并不是等效的,只是因为有热点。虚拟机设计团队选择将GC的世代集合扩展到方法区域,或者使用永久生成来实现方法区域。
Java虚拟机规范对此区域有非常宽松的限制。除了与Java堆相同外,它不需要连续的内存,可以选择固定大小或可扩展大小。您也可以选择不实施垃圾收集。相对而言,垃圾回收行为在该区域相对较少,但并不是数据作为永久代的名称以“永久”的方式进入方法区域。该区域内存恢复的目标主要是恢复常量池和卸载类型。一般来说,该区域的恢复“分数”更难以满足,尤其是类型的卸载。条件非常严酷,但是在此部分区域的回收确实是必要的。
根据Java虚拟机规范,当方法区域不能满足内存分配要求时,将引发OutOfMemoryError异常。
方法区域有时称为PermGen(PermGen)。

所有对象在实例化后的整个运行周期中都存储在堆内存中。堆内存分为不同的部分:伊甸园,幸存者空间和旧世空间。
方法的执行伴随着线程。局部变量和原始类型的引用存储程堆栈中。引用关联的对象(例如String)都存在于堆中。为了更好地理解以上段落,我们可以看一个示例:

该程序的数据按如下方式存储在内存中:


通过JConsole工具,您可以查看有关正在运行的Java程序(例如Eclipse)的一些信息:堆内存分配,线程数和已装入的类数;

程序计数器寄存器
程序计数器寄存器是一个很小的存储空间,其功能可以看作是当前线程执行的字节码的行号指示符。在虚拟机的概念模型(仅概念模型中,可以以某些更有效的方式实现各种虚拟机),字节码解释器通过更改此计数器的值以选择要执行的下一个计数器来工作。字节码指令,分支,循环,跳转,异常处理和线程恢复都需要依靠此计数器来完成。
由于Java虚拟机的多线程是通过线程交替切换和分配处理器执行时间的方式实现的,因此在任何时候,处理器(对于多核处理器来说就是核心)将仅执行线程中的指令。因此,为了程切换后恢复到正确的执行位置,每个线程都需要具有一个独立的程序计数器。线程之间的计数器不会互相影响,而是独立存储。我们称这种类型的内存区域为“线程专用”内存。
如果线程正在执行Java方法,则此计数器记录正在执行的虚拟机的字节码指令的地址;如果线程正在执行Natvie方法,则计数器值为空(未定义)。
此内存区域是Java虚拟机规范中唯一未指定任何OutOfMemoryError条件的区域。
JVM堆栈(JVM堆栈)
就像程序计数器一样,Java虚拟机堆栈(Java虚拟机堆栈)也是线程专用的,并且其生命周期与线程的生命周期相同。虚拟机堆栈描述了Java方法执行的内存模型:执行每个方法时,会同时创建一个堆栈帧以存储诸如局部变量表,操作堆栈,动态链接和方法退出之类的信息。从调用每种方法到执行完成的过程,对应于虚拟机堆栈中从推入到弹出的堆栈帧的过程。
局部变量表存储在编译时已知的各种基本数据类型(布尔,字节,字符,短型,整型,浮点型,长型,双精度型),对象引用(引用类型,它并不等同于对象本身),在虚拟机实现中,它可以是指向对象起始地址的引用指针,也可以指向代表对象或与该对象相关的其他位置的句柄)和returnAddress类型(指向对象的地址)字节码指令)。
64位长和双精度数据将占据两个局部变量空间(Slot),其余数据类型将仅占据一个。局部变量表所需的内存空间是在编译期间分配的。输入方法时,将完全确定该方法需要在框架中分配多少局部变量空间,并且局部变量表的大小在方法运行期间不会更改。
在Java虚拟机规范中,为此区域指定了两个异常条件:如果线程请求的堆栈深度大于虚拟机允许的深度,则将引发StackOverflowError异常;否则,将抛出异常。如果可以动态扩展虚拟机堆栈(当前可以动态扩展Java虚拟机的很大一部分,但是Java虚拟机规范还允许使用固定长度的虚拟机堆栈)。当扩展无法申请足够的内存时,将引发OutOfMemoryError异常。
本机方法堆栈(本机方法堆栈)
本机方法堆栈(本机方法堆栈)和虚拟机堆栈起着非常相似的作用。区别在于,虚拟机堆栈为虚拟机提供服务以执行Java方法(即字节码),而本机方法堆栈则为虚拟机使用的本机方法提供服务。本地方法堆栈中方法的语言,用法和数据结构在虚拟机规范中不是强制性的,因此特定的虚拟机可以自由地实现它。甚至某些虚拟机(例如Sun HotSpot虚拟机)都将本地方法堆栈和虚拟机堆栈直接组合为一个。与虚拟机堆栈一样,本地方法堆栈区域也会引发StackOverflowError和OutOfMemoryError异常。
OutOfMemoryError在哪里
清楚地了解内存结构也可以帮助您了解不同的OutOfMemoryErrors:

Exception in thread “main”:java.lang.OutOfMemoryError:Java heap space
原因:无法将对象分配给堆内存
Exception in thread “main”: java.lang.OutOfMemoryError:PermGen space
原因:无法将类或方法加载到旧版本中。程序加载许多类时可能会出现,例如,引用了许多第三方库;
Exception in thread “main”:java.lang.OutOfMemoryError:Requested array size exceeds VM limit
原因:创建的数组大于堆内存的空间
Exception in thread “main”: java.lang.OutOfMemoryError: requestbytes for .Out of swap space?
原因:本地分配失败。 JNI,本机库或Java虚拟机将从本地堆中分配内存空间。
Exception in thread “main”: java.lang.OutOfMemoryError:(Native method)
原因:相同的本地方法内存分配失败,但是是由JNI或本地方法或Java虚拟机发现的
原创:纯洁的笑容
维基百科对JVM的介绍
基于Java虚拟机规范Java SE 7版的Java虚拟机(JVM)架构概述
Java虚拟机(JVM)是使计算机能够运行Java程序的抽象计算机。 JVM有三种概念:规范,实现和实例。该规范是正式描述JVM实现要求的文档。具有单一规范可确保所有实现都是可互操作的。 JVM实现是满足JVM规范要求的计算机程序。 JVM的实例是在进程中运行的实现,该进程执行编译为Java字节码的计算机程序。
Java运行时环境(JRE)是一个软件包,其中包含运行Java程序所需的软件。它包括Java虚拟机实现以及Java类库的实现。拥有Java商标的Oracle公司通过其名为HotSpot的Java虚拟机分发Java运行时环境。
Java开发工具包(JDK)是JRE的超集,包含用于Java程序员的工具,例如javaccompiler。直接由Oracle Corporation或由Oracle管理的OpenJDK开源项目免费提供Java开发工具包。
本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/shoujiruanjian/article-370445-1.html
枷锁在一根根往自己脖子上套
我也遇到过一次