iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > Python >Java 内存安全问题的注意事项
  • 762
分享到

Java 内存安全问题的注意事项

2024-04-02 19:04:59 762人浏览 安东尼

Python 官方文档:入门教程 => 点击学习

摘要

目录前言内存管理Java各版本内存管理改进内存溢出堆内存溢出栈溢出运行时常量池溢出方法区溢出元空间溢出本机直接内存溢出常见案例问题排查前言 Java在内存管理方面是要比C/C++更

前言

Java在内存管理方面是要比C/C++更方便的,不需要为每一个对象编写释放内存的代码,JVM虚拟机将为我们选择合适的时间释放内存空间,使得程序不容易出现内存泄漏和溢出的问题

不过,也正是因为Java把内存控制的权利交给了Java虚拟机,一旦出现内存泄漏和溢出方面的问题,如果不了解虚拟机是怎么使用内存的,那排查错误将会成为一项异常艰难的工作

下面先看看JVM如何管理内存的

内存管理

根据Java虚拟机规范(第3版) 的规定,Java虚拟机所管理的内存将会包括以下几个运行内存数据区域:

  • 线程隔离数据区:
    • 程序计数器: 当前线程所执行字节码的行号指示器
    • 虚拟机栈: 里面的元素叫栈帧,存储局部变量表、操作栈、动态链接、方法出口等,方法被调用到执行完成的过程对应一个栈帧在虚拟机栈中入栈到出栈的过程。
    • 本地方法栈: 和虚拟机栈的区别在于虚拟机栈为虚拟机执行Java方法,本地方法栈为虚拟机使用到的本地Native方法服务。
  • 线程共享数据区:
    • 方法区: 可以描述为堆的一个逻辑部分,或者说使用永久代来实现方法区。存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
    • 堆: 唯一目的就是存放对象的实例,是垃圾回收管理器的主要区域,分为Eden、From/To Survivor空间。

Java各版本内存管理改进

下图中永久代理解为堆的逻辑区域,移除永久代的工作从jdk7就已经开始了,部分永久代中的数据(常量池)在JDK7中就已经转移到了堆中,JDK8中直接去除了永久代,方法区中的数据大部分被移到堆里面,还剩下一些元数据被保存在元空间里

内存溢出

  • 内存泄露Memory Leak: 申请的内存空间没有及时释放,导致后续程序里这块内容永远被占用。
  • 内存溢出Out Of Memory: 要求的内存超过了系统所能提供的

运行时数据区域的常见异常

在JVM中,除了程序计数器外,虚拟机内存的其他几个运行时数据区域都有发生OOM异常的可能。

堆内存溢出

不断的创建对象,并且保证GC Roots到对象之间有可达路径来避免垃圾回收机制清除这些对象。


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

栈溢出

单个线程下不断扩大栈的深度引起栈溢出。


public class StackSOF {
    private int stackLength = 1;
    public void stackLeak() {
        stackLength++;
        stackLeak();
    }
    public static void main(String[] args) {
        StackSOF sof = new StackSOF();
        try {
            sof.stackLeak();
        } catch (Throwable e) {
            System.out.println("Stack Length: " + sof.stackLength);
            throw e;
        }
    }
}

循环的创建线程,达到最大栈容量。


public class StackOOM {
    private void dontStop() {
        while (true) {
        }
    }
    public void stackLeadByThread() {
        while (true) {
            Thread thread = new Thread(new Runnable() {
                @Override
                public void run() {
                    dontStop();
                }
            });
            thread.start();
        }
    }
    public static void main(String[] args) {
        StackOOM stackOOM = new StackOOM();
        stackOOM.stackLeadByThread();
    }
}

运行时常量池溢出

不断的在常量池中新建String,并且保持引用不释放。


public class RuntimeConstantPoolOOM {
    public static void main(String[] args) {
        // 使用List保持着常量池的引用,避免Full GC回收常量池
        List<String> list = new ArrayList<String>();
        int i = 0;
        while (true) {
            // intern()方法使String放入常量池
            list.add(String.valueOf(i++).intern());
        }
    }
}

方法区溢出

借助CGLib直接操作字节码运行时产生大量的动态类,最终撑爆内存导致方法区溢出。


public class MethodAreaOOM {
    static class ObjectInMethod {
    }
    public static void main(final String[] args) {
        // 借助CGLib实现
        while (true) {
            Enhancer enhancer = new Enhancer();
            enhancer.setSuperclass(ObjectInMethod.class);
            enhancer.setUseCache(false);
            enhancer.setCallback(new MethodInterceptor() {
                @Override
                public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                    return methodProxy.invokeSuper(o, objects);
                }
            });
            enhancer.create();
        }
    }
}

元空间溢出

助CG Lib运行时产生大量动态类,唯一的区别在于运行环境修改为Java 1.8,设置-XX:MaxMetaspaceSize参数,便可以收获java.lang.OutOfMemoryError: Metaspace这一报错

本机直接内存溢出

直接申请分配内存(实际上并没有真正向操作系统申请分配内存,而是通过计算得知内存无法分配,于是抛出异常)


public class DirectMemoryOOM {
    private static final int _1MB = 1024 * 1024;
    public static void main(String[] args) throws IllegalAccessException {
        Field unsafeField = Unsafe.class.getDeclaredFields()[0];
        unsafeField.setAccessible(true);
        Unsafe unsafe = (Unsafe) unsafeField.get(null);
        while (true) {
            unsafe.allocateMemory(_1MB);
        }
    }
}

常见案例

在工作中一般会遇到有以下几种情况导致内存问题

  • 传输数据量过大

因为传输数量过大、或一些极端情况导致代码中间结果对象数据量过大,过大的数据量撑爆内存

  • 查询出大量对象

这个多为sql语句设置问题,SQL未设置分页,用户一次查询数据量过大、频繁查询SQL导致内存堆积、或是未作判空处理导致WHERE条件为空查询出超大数据量等

  • 接口性能问题导致

这类为外部接口性能较慢,占用内存较大,并且短时间内高QPS导致的,导致服务内存不足,线程堆积或挂起进而出现FullGC

  • 元空间问题

使用了大量的反射代码,Java字节码存取器生成的类不断生成

问题排查

使用jmap分析内存泄漏

1.生成dump文件


jmap -dump:fORMat=b,file=/xx/xx/xx.hprof pid

2.dump文件下载到本地

3.dump文件分析

可以使用MAT,MAT可作为Eclipse插件或一个独立软件使用,MAT是一个高性能、具备丰富功能的Java堆内存分析工具,主要用来排查内存泄漏和内存浪费的问题。

使用MAT打开上一部后缀名.hprof的dump文件

  • Histogram:直方图,各个类的实例,包括个数和大小,可以查看类引用和被引用的路径。
  • Dominator Tree:支配图,列出所有线程和线程下面的那些对象占用的空间。
  • Top Consumers:通过图形列出消耗内存多的实例。
  • Leak Suspects:MAT自动分析的内存泄漏报表

可以用这个工具分析出什么对象什么线程占用内存空间较大,对象是被什么引用的,线程内有哪些资源占用很高

以运行时常量池溢出为例

打开Histogram类实例表

Objects是类的对象的数量;Shallow是对象本身占用内存大小、不包含其他引用;

Retained是对象自己的Shallow加上直接或间接访问到对象的Shallow之和,也可以说是GC之后可以回收的内存总和

从图中可以看出运行时常量池溢出的情况,产生了大量的String和char[]实例

在char[]上右键可以得到上图所有char[]对象的被引用路径,可以看出这些char数组都是以String的形式存在ArrayList中,并且是由main这个线程运行的

可以看出是main线程中新建了一个数组,其中存了32w+个长度为6的char数组组成的String造成的内存溢出

关于MAT的详细使用可以从MAT官方教程学习更多

以上就是Java 内存安全问题的注意事项的详细内容,更多关于Java 内存安全问题的资料请关注编程网其它相关文章!

--结束END--

本文标题: Java 内存安全问题的注意事项

本文链接: https://www.lsjlt.com/news/127703.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Java 内存安全问题的注意事项
    目录前言内存管理Java各版本内存管理改进内存溢出堆内存溢出栈溢出运行时常量池溢出方法区溢出元空间溢出本机直接内存溢出常见案例问题排查前言 Java在内存管理方面是要比C/C++更...
    99+
    2024-04-02
  • Java中内存安全问题的注意事项有哪些
    这篇文章给大家分享的是有关Java中内存安全问题的注意事项有哪些的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。前言Java在内存管理方面是要比C/C++更方便的,不需要为每一个对象编写释放内存的代码,JVM虚拟机...
    99+
    2023-06-15
  • Python开发注意事项:避免常见的内存泄漏问题
    Python作为一种高级编程语言,具有易学易用和开发效率高等优点,在开发人员中越来越受欢迎。但是,由于其垃圾回收机制的实现方式,Python在处理大量内存时,容易出现内存泄漏问题。本文将从常见内存泄漏问题、引起问题的原因以及避免内存泄漏的方...
    99+
    2023-11-22
    内存泄漏 注意事项 Python开发
  • Golang开发注意事项:如何避免内存泄露问题
    Golang是一种快速、高效的开发语言,以其强大的并发能力和内置的垃圾回收机制而受到广泛的欢迎。然而,即使在使用Golang进行开发时,仍然有可能遇到内存泄露的问题。本文将介绍一些常见的Golang开发注意事项,以帮助开发者避免内存泄露问题...
    99+
    2023-11-23
    Golang 内存泄露 避免
  • Golang开发注意事项:如何避免内存溢出问题
    Golang是一种强大的编程语言,但在开发过程中,开发者仍然需要谨慎处理内存管理,以避免出现内存泄漏和内存溢出问题。本文将从内存管理的重要性入手,介绍Golang开发中避免内存溢出问题的注意事项和技巧。1. 内存管理的重要性内存管理在软件开...
    99+
    2023-11-22
    内存管理 性能优化 异常处理
  • 安全第一:CMS 主题开发中的安全注意事项
    在 CMS 主题开发中,安全是最为重要的环节之一,它不仅关系到网站的正常运行,也关系到用户的数据安全和隐私。以下是一些 CMS 主题开发中的安全注意事项,希望能帮助您避免潜在的安全风险: 使用安全可靠的代码库和组件: 在开发 CM...
    99+
    2024-02-11
    CMS 主题开发 安全 注意事项 Web 开发
  • Java安全之Tomcat6Filter内存马问题
    目录回顾Tomcat8打法探索Tomcat6与Tomcat8之间的区别回顾Tomcat8打法 先回顾下之前Tomcat789的打法 这里先抛开 7 8之间的区别, 在8中,最后add...
    99+
    2022-11-13
    Java安全Tomcat6 Filter内存马 Java Tomcat6内存马 Tomcat Filter内存马
  • Golang函数库的安全注意事项
    使用 go 函数库时,需要考虑以下安全注意事项:定期更新依赖项,确保没有已知漏洞。验证和清理用户输入,以防止注入攻击。使用经过验证的加密算法来处理敏感数据。处理函数库引发的错误,并采取适...
    99+
    2024-04-18
    golang 函数库安全 敏感数据
  • Golang开发注意事项:如何处理并发安全性问题
    在当今互联网时代,由于系统需求复杂度的增加,对高并发性能和安全的要求也变得越发迫切。Golang作为一种并发编程语言,以其简洁高效的特性而备受青睐。然而,开发人员在使用Golang进行并发编程时,必须时刻关注并处理并发安全性问题。在本文中,...
    99+
    2023-11-22
    Golang 并发 安全性
  • Golang闭包的线程安全注意事项
    当在并发环境中使用闭包时,引用类型闭包(捕获引用类型变量的闭包)必须线程安全,因为对其的修改会影响原始变量。使引用类型闭包线程安全的两种主要方法是:使用互斥锁,或使用不可变数据结构。 ...
    99+
    2024-04-16
    golang 闭包 作用域
  • python切片中内存的注意事项总结
    1、由于 Python 列表的切片会在内存中创建新对象,因此需要注意的另一个重要函数是itertools.islice。 2、通常需要遍历切片,而不仅仅是在内存中静态创建它。isli...
    99+
    2024-04-02
  • 使用python时注意的内存、缓存问题
    1. 在使用python时,常常会出现Memory Error,主要是由于python不会自动回收内存,造成内存一直占用,可以采取手动释放内存的方法,详见http://blog.csdn.net/nirendao/article/deta...
    99+
    2023-01-31
    缓存 内存 python
  • PHP 函数调用中的安全注意事项
    php 函数调用中的安全注意事项:验证用户输入,确保格式正确且无恶意字符。避免使用 * 通配符参数,因为它允许攻击者指定任意参数。使用类型标注和类型检查,确保参数具有正确的类型和格式。小...
    99+
    2024-04-17
    安全 php 敏感数据 lsp
  • VS2003安装的注意事项
    这篇文章主要为大家展示了“VS2003安装的注意事项”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“VS2003安装的注意事项”这篇文章吧。1、VS2003安装需求1.1VS2003安装硬件:CP...
    99+
    2023-06-17
  • python切片中内存的注意事项有哪些
    这篇文章主要介绍了python切片中内存的注意事项有哪些,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。1、由于 Python 列表的切片会在内存中创建新对象,因此需要注意的另...
    99+
    2023-06-20
  • python切片中内存的注意事项是什么
    这篇文章主要介绍了python切片中内存的注意事项是什么,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。由于 Python 列表的切片会在内存中创建新对象,因此需要注意的另一个...
    99+
    2023-06-20
  • Java中Collections.emptyList()的注意事项
    偶然发现有小伙伴错误地使用了Collections.emptyList()方法,这里记录一下。她的使用方式是: public void run() { ...... Li...
    99+
    2024-04-02
  • PHP中使用Memcache缓存需要注意的安全问题
    随着Web应用程序的不断发展,缓存的使用越来越普遍。Memcache是一种广泛使用的缓存技术,可以提高Web应用程序的性能。然而,Memcache缓存的使用同样存在一些安全问题,尤其是在PHP中使用时。以下是PHP中使用Memcache缓存...
    99+
    2023-05-15
    PHP 安全问题 Memcache缓存
  • mysql安全设置注意事项是什么
    这篇文章主要为大家展示了“mysql安全设置注意事项是什么”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“mysql安全设置注意事项是什么”这篇文章吧。  1.如...
    99+
    2024-04-02
  • java成员内部类的注意事项有哪些
    1. 成员内部类不能有静态成员(静态字段、静态方法),除非静态成员是final和static的常量。2. 成员内部类可以访问外部类的...
    99+
    2023-09-26
    java
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作