[/b][b]运行时数据区:方法区、虚拟机栈、本地方法栈、堆、程序计数器。
程序计数器:作用是当前线程所执行的字节码的行号指示器。字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令。
分支、循环、跳转、异常处理、线程恢复等都是依赖这个计数器来完成。
在任何一个确定的时刻,一个处理器只会执行一条线程中的指令。
Java虚拟机栈:也是线程私有的,每个方法被执行的时候都会同时创建一个栈帧,用于存储局部变量表、操作栈、动态链接、方法出口等信息,
Java 虚拟机规范中规定了两种异常状况:如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverFlowError异常,
如果虚拟机栈可以动态扩展,当扩展无法申请到足够的内存时会抛出OutOfMemoryError异常
本地方法栈:为虚拟机使用到的Native方法服务。本地方法栈也会抛出StackOverFlowError和OutOfMemoryError异常。
Java堆:java虚拟机管理内存中最大的一块,被所有线程共享的一块内存,所有对象实例以及数组都要在堆上分配内存。Java堆是垃圾回收的主要区域。
Java堆还可以分为新生代和年老代。
java堆处于物理上不连续的区域 可通过-Xmx和-Xms控制扩展大小,如果堆中没有内存完成实例分配并且堆也无法扩展时,将会抛出OutOfMemoryError异常。
方法区:各个线程共享的内存。用于存储已经被虚拟机加载的类信息、常量、静态变量等信息
运行时常量池:是方法区的一部分,用于存放编译期生成的各种字面变量和符号引用,这部分内容将在类加载后存放到方法区的运行时常量池中。
运行时常量池相对于Class文件常量池的另外一个重要的特性是动态性。运行期间也可能将新的常量放入池中,用的最多的是String类的intern()方法。
对象的访问:
对于代码Object obj=new Object();
首先java本地变量表中存储一个引用,而new Object又会在堆中开辟内存空间。
另外,java堆中还必须包含能查找到此对象类型的数据。(如:对象类型、父类型、实现的接口、方法等)的地址信息,这些类型数据存储在方法区中。
主流的访问方式为1:使用句柄 2.直接指针
内存溢出的代码:
public class HeapOOM{
static class OOMObject{}
public static void main(String[] args)
{
List<OOMObject> list=new ArrayList<OOMObject>();
while(true)
list.add(new OOMObject());
}
}
虚拟机栈和本地方法栈的溢出:
HotSpot虚拟机不区分虚拟机栈和本地方法栈,栈容量只由-Xss参数设定。
如果线程请求的栈深度大于虚拟机所允许的最大深度,将抛出StackOverFlowError异常
如果虚拟机在扩展栈时无法申请到足够的内存空间,则抛出OutOfMemoryError异常。
看如下代码:
public class JavaVMStackOF{
public int stackLength;
public void stackLeak(){
stackLength++;
stackLeak();
}
public static void main(String[] args){
JavaVMStackOF oom=new JavaVMStackOF();
oom.stackLeak();
}
}
以上代码会出现StackOverFlowError异常。实验证明在单线程下无论是栈帧太大还是虚拟机栈容量太小虚拟机抛出的都是StackOverFlowError异常。
操作系统分配给每个进程内存有限:
栈内存=可分配内存限制(win 32位为2G)-Xmx(最大堆容量)-MaxPermSize(最大方法区容量)-程序计数器容量(忽略)
注意:每个线程分配的栈容量越大,可建立的线程数量则减小,建立线程时越容易把剩余内存耗尽。
public class JavaVMStackOOM{
private void dontStop(){
while(true){
}
}
public void stackLeakByThread(){
while(true){
Thread thread=new Thread(new Runnable(){
public void run(){
dontStop();
}
});
thread.start();
}
}
public static void main(String[] args){
JavaVMStackOOM oom=new JavaVMStackOOM()'
oom.stackLeakByThread();
}
}
运行时常量池溢出:
实例代码如下:
public class RuntimePoolOOM {
public static void main(String[] args){
List<String> list=new ArrayList<String>();
int i=0;
while(true){
//String.intern()方法作用是:如果池中已经包含一个等与此String对象的字符串,直接返回 否则将String对象中包含的字符串添加到常量池中。
list.add(String.valueOf(i++).intern());
}
}
运行结果如下:Exception in thread "main" java.lang.OutOfMemoryError: PermGen space
at java.lang.String.intern(Native Method)
at com.test.jvm.RuntimePoolOOM.main (RuntimePoolOOM.java:16)
}
分享到:
相关推荐
JVM 内存区域组成包括栈内存和堆内存。栈内存用于存放基本类型变量和对象的引用变量,而堆内存用于存放由 new 创建的对象和数组。堆的优势是可以动态分配内存大小,生存期也不必事先告诉编译器,但缺点是要在运行时...
深入理解JVM内存区域与内存溢出异常
了解JVM内存结构是理解内存溢出的关键。 #### 二、JVM运行时数据区域 - **程序计数器(Program Counter Register)**:当前线程所执行的字节码的行号指示器。每条线程拥有独立的程序计数器,因此它属于线程私有区域...
理解JVM内存结构和内存分配机制对于避免内存溢出(OutOfMemoryError)、提升程序性能、减少垃圾回收开销至关重要。开发者应关注内存配置、对象生命周期管理以及适当的垃圾回收策略,以优化应用程序的性能和稳定性。
【初探JVM内存区域】 Java虚拟机(JVM)是Java编程语言的核心组成部分,它为Java应用程序提供了运行环境。理解JVM内存区域对于优化Java应用性能至关重要。本篇文章将详细探讨JVM中的主要内存区域及其作用。 1. **...
1. **堆内存(Heap)**:这是程序共享的内存区域,用于存储对象实例和数组。 2. **方法区(Method Area)**:用于存储类的信息、静态变量、常量池等数据。 3. **栈内存(Stack)**:每个线程都有一个私有的栈,用于存储...
【JVM内存溢出】指的是Java虚拟机在运行过程中,由于内存分配不当或者内存使用过度导致内存无法正常管理,从而抛出错误的情况。这通常会导致应用程序崩溃或性能急剧下降。在Tomcat这样的Java应用服务器中,内存溢出...
JVM内存主要分为以下几个区域: - **方法区(Method Area)**:这是所有线程共享的区域,存储类信息、常量、静态变量、即时编译后的代码等。在Java 8以前,这部分也被称为永久代(Permanent Generation),在...
虽然理论上永久代不需要频繁进行垃圾回收,但在实践中仍然有可能发生内存溢出。例如,当加载了大量的类并且没有足够的内存来存储这些类时,就会出现永久代溢出。 #### 七、结论 通过以上内容可以看出,深入理解JVM...
### JVM实战-对象访问与内存溢出异常解析 #### 实验背景与目标 在Java虚拟机(JVM)中,不同的内存区域负责不同的功能,并且各自可能会出现特定类型的内存溢出异常。通过本实验,旨在深入理解JVM内存管理机制以及...
### Java虚拟机(JVM)内存设置与调优详解 ...通过对JVM内存管理机制的理解,结合具体的应用场景,开发者可以有效地避免内存溢出错误,确保应用稳定高效地运行。希望本文能为您的Java项目提供有力的技术支持。
Java虚拟机(JVM)内存模型是Java编程中不可或缺的一部分,它主要分为以下几个分区: ...此外,了解这些内存区域的工作原理也能帮助开发者在遇到栈溢出或内存溢出等问题时,更快地定位和解决问题。
4. **内存溢出问题** - **栈溢出**:如果栈帧过大或者线程太多,可能导致栈空间不足,出现StackOverflowError。 - **堆溢出**:如果创建太多对象或对象占用内存过大,堆内存可能会耗尽,抛出OutOfMemoryError。 5...
JVM内存主要分为几个区域:堆内存(Heap)、栈内存(Stack)、方法区(Method Area)、程序计数器(PC Register)和本地方法栈(Native Method Stack)。内存使用过高可能导致内存溢出,影响程序运行效率,甚至导致...
- **特性**:极小的内存空间,几乎不会导致内存溢出。 #### 四、类加载机制与JDK调优工具 - **类加载机制**:Java类被加载到JVM的过程涉及多个阶段,包括加载、验证、准备、解析和初始化。了解这一过程有助于优化...
标题中的“关于tomcat乱码以及tomcat jvm 内存溢出问题的解决方案和理论”涉及了两个关键的IT概念:Tomcat服务器的字符编码问题和Java虚拟机(JVM)内存管理的问题。让我们逐一深入探讨这两个主题。 首先,我们来...
了解这些内存区域后,我们来谈谈JVM内存调优。调优主要包括以下几个方面: 1. 设置合理的堆大小:过大可能导致内存浪费,过小则可能导致频繁的垃圾收集。可以通过-Xms和-Xmx设置初始堆大小和最大堆大小。 2. 年轻...
Heap space 是 JVM 管理的堆内存区域,这块内存主要是被 JVM 存放对象实例的。如果程序中创建了太多对象,而没有及时释放,将会导致内存溢出。 内存溢出问题是 Java 开发中常见的错误,通过调整容器参数和优化程序...
"JVM内存区域划分" JVM内存区域划分是Java虚拟机(JVM)中的一种内存管理机制,...JVM内存区域划分是Java虚拟机中的一种重要机制,通过不同的区域来管理内存,避免内存溢出和其他问题,从而确保Java程序的正确执行。
JVM内存模型与垃圾回收是Java性能优化的关键部分。JVM(Java Virtual Machine)内存模型分为多个区域,包括新生代(New Generation)、老年代(Old Generation)和永久代(Permanent Generation)。新生代又细分为...