HotSpot 自动内存管理笔记与实战

简介: 1.对象的创建 虚拟机遇到一条new指令时,首先会去检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否已被加载、解析和初始化过。如果没有,则必须先进行相应的类的加载。

1.对象的创建
虚拟机遇到一条new指令时,首先会去检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否已被加载、解析和初始化过。如果没有,则必须先进行相应的类的加载。

2、对象的访问定位
简历对象是为了使用对象,我们的java程序需要通过栈上的refrerence数据来操作堆上的具体对象。由于reference类型在java虚拟机规范中只规定了一个指向对象的引用,并没有定义这个引用应该通过何种方式去定位、访问堆中的对象的具体位置,所以对象访问方式也是取决于虚拟机实现而定的。目前主流的访问方式有使用句柄和直接指针两种。

使用句柄:那么 java堆中会划分出一块内存来作为句柄池,reference中存储的就是对象的句柄地址,而句柄中包含了对象实例数据与类型数据各自的具体地址信息。

 

使用直接指针:那么Java堆对象的布局中就必须考虑如何放置访问类型数据的相关信息,而reference中存储的直接就是对象地址。

  使用句柄来访问的最大好处就是refernce中存储的是稳定的句柄地址,在对象被移动时,将会改变句柄中的实例数据指针,而reference本身不需要修改。

  使用直接指针访问方式的最大好处就是速度更快,它节省了一次指针定位的时间开销,由于对象的访问在JAVA中非常频繁,因此这类开销积少成多后也是一项非常可观的执行成本。

 

3、JAVA堆溢出

  JAVA堆用于存储对象实例,不断地创建对象,并保证GC, Root到对象之间有可达路径来避免垃圾回收机制清除这些对象,那么在对象数量到达最大堆的容量限制后就会产生内存溢出异常。  

  下面设置运行参数为 -Xms521M -Xmx512M -XX:+HeapDumpOnOutOfMemoryError,让虚拟机出现内存溢出异常时Dump出当前的内存堆转储快照以便事后进行分析。

package JVMtest;

import java.util.ArrayList;
import java.util.List;

public class HeapOOM {
    static class OOMObject{
        
    }
    
    public static void main(String[] args){
        List<OOMObject> list = new ArrayList<OOMObject>();
        while(true){
            list.add(new OOMObject());
        }
    }
}

  将堆的最小值-Xms参数与最大值-Xmx参数设置为一样即可避免堆自动扩展

 

4、虚拟机栈和本地方法栈溢出

  栈容量只由-Xss参数设定。关于虚拟机栈和本地方法栈,在JAVA虚拟机规范中描述了两种异常:

  (1)如果线程请求的栈深度大于虚拟机所允许的最大深度,将抛出StackOverflowError异常。

  (2)如果虚拟机在扩展栈时无法申请到足够的内存空间,则抛出OutOfMemoryError异常。

  测试时,通过不断地创建线程的方式倒是可以产生内存溢出异常,但这样产生的内存溢出异常与栈空间是否足够大并不存在任何联系,或者再准确的说,在这种情况下,为每个线程的栈分配的内存越大,反而越容易产生内存溢出的异常。原因是,操作系统分配给每个进程的内存是有限制的,譬如32为的Windows限制为2GB,虚拟机提供了参数来控制JAVA堆和方法去的两部分最大的内存值。那么剩下的内存为,操作系统限制的2GB-Xms(最大堆容量)-MaxPermSize(最大方法区容量),程序计数器消耗内存很小,可以忽略。如果虚拟机本身消耗的内存不计算在内,剩下的内存就由虚拟机和本地方法栈瓜分了。每个线程分配到的栈容量越大,可以建立的线程数量自然就减少,建立线程时,就很容易把剩下的内存耗尽。

package JVMtest;

public class JavaVMStackOOM {
    private void dontStop(){
        while(true){
            
        }
    }
    
    public void stackLeankByThread(){
        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.stackLeankByThread();
    }
}

 

5、方法区和运行时异常量池溢出

  比如String.intern()是一个Native方法,作用是,如果字符串常量池中已经包含一个等于此String对象的字符串,则返回带包翅中这个字符串的String对象;否则,将此String对象包含的字符串添加到常量池中,并且返回此String对象的引用。

  方法区用于存放Class的相关信息,如类名、访问修饰符、常量池、字段描述、方法描述等。这些区域的测试,基恩的思路是运行时产生大量的类去填满方法区,直到溢出。

  

package JVMtest;

import java.lang.reflect.Method;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

public class JavaMethodAreaOOM {
    public static void main(String args[]){
    while(true){
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(OOMObject.class);
        enhancer.setUseCache(false);
        enhancer.setCallback(new MethodInterceptor(){

            @Override
            public Object intercept(Object obj, Method method, Object[] args,
                    MethodProxy proxy) throws Throwable {
                return proxy.invokeSuper(obj,args);
            }

        });
        enhancer.create();
    }
    }
    static class OOMObject{
        
    }
}

 

目录
相关文章
|
21天前
|
存储 弹性计算 算法
前端大模型应用笔记(四):如何在资源受限例如1核和1G内存的端侧或ECS上运行一个合适的向量存储库及如何优化
本文探讨了在资源受限的嵌入式设备(如1核处理器和1GB内存)上实现高效向量存储和检索的方法,旨在支持端侧大模型应用。文章分析了Annoy、HNSWLib、NMSLib、FLANN、VP-Trees和Lshbox等向量存储库的特点与适用场景,推荐Annoy作为多数情况下的首选方案,并提出了数据预处理、索引优化、查询优化等策略以提升性能。通过这些方法,即使在资源受限的环境中也能实现高效的向量检索。
|
23天前
|
存储 监控 算法
JVM调优深度剖析:内存模型、垃圾收集、工具与实战
【10月更文挑战第9天】在Java开发领域,Java虚拟机(JVM)的性能调优是构建高性能、高并发系统不可或缺的一部分。作为一名资深架构师,深入理解JVM的内存模型、垃圾收集机制、调优工具及其实现原理,对于提升系统的整体性能和稳定性至关重要。本文将深入探讨这些内容,并提供针对单机几十万并发系统的JVM调优策略和Java代码示例。
45 2
|
2月前
|
缓存 Java 测试技术
谷粒商城笔记+踩坑(11)——性能压测和调优,JMeter压力测试+jvisualvm监控性能+资源动静分离+修改堆内存
使用JMeter对项目各个接口进行压力测试,并对前端进行动静分离优化,优化三级分类查询接口的性能
谷粒商城笔记+踩坑(11)——性能压测和调优,JMeter压力测试+jvisualvm监控性能+资源动静分离+修改堆内存
|
22天前
|
存储 前端开发 Java
Kotlin教程笔记 - MVVM架构怎样避免内存泄漏
Kotlin教程笔记 - MVVM架构怎样避免内存泄漏
|
25天前
|
存储 前端开发 Java
Kotlin教程笔记 - MVVM架构怎样避免内存泄漏
Kotlin教程笔记 - MVVM架构怎样避免内存泄漏
41 0
|
3月前
|
NoSQL Java 测试技术
Golang内存分析工具gctrace和pprof实战
文章详细介绍了Golang的两个内存分析工具gctrace和pprof的使用方法,通过实例分析展示了如何通过gctrace跟踪GC的不同阶段耗时与内存量对比,以及如何使用pprof进行内存分析和调优。
79 0
Golang内存分析工具gctrace和pprof实战
|
3月前
|
存储 缓存 编译器
Linux源码阅读笔记06-RCU机制和内存优化屏障
Linux源码阅读笔记06-RCU机制和内存优化屏障
|
6月前
|
算法 Java Python
【Python 的内存管理机制专栏】Python 内存管理实战:性能优化与内存泄漏检测
【5月更文挑战第18天】Python内存管理关乎程序性能与稳定性。优化包括避免过多临时对象,如优化列表推导式减少对象创建。警惕循环引用造成的内存泄漏,如示例中的Node类。使用`gc`模块检测泄漏,通过`gc.set_debug(gc.DEBUG_LEAK)`和`gc.collect()`获取信息。实践中需持续分析内存使用,优化算法、数据结构和资源释放,以提升程序质量与效率。
71 9
【Python 的内存管理机制专栏】Python 内存管理实战:性能优化与内存泄漏检测
|
5月前
|
存储 安全 Java
SpringSecurity6从入门到实战之初始用户如何存储到内存
Spring Security 在 SpringBoot 应用中默认使用 `UserDetailsServiceAutoConfiguration` 类将用户信息存储到内存中。当classpath有`AuthenticationManager`、存在`ObjectPostProcessor`实例且无特定安全bean时,此配置生效。`inMemoryUserDetailsManager()`方法创建内存用户,通过`UserDetails`对象填充`InMemoryUserDetailsManager`的内部map。若要持久化到数据库,需自定义`UserDetailsService`接口实
|
4月前
|
算法 Java 开发者
Java面试题:Java内存探秘与多线程并发实战,Java内存模型及分区:理解Java堆、栈、方法区等内存区域的作用,垃圾收集机制:掌握常见的垃圾收集算法及其优缺点
Java面试题:Java内存探秘与多线程并发实战,Java内存模型及分区:理解Java堆、栈、方法区等内存区域的作用,垃圾收集机制:掌握常见的垃圾收集算法及其优缺点
37 0