导航:首页 > 编程语言 > java内存泄露内存溢出

java内存泄露内存溢出

发布时间:2025-04-26 14:08:20

A. java内存溢出OutOfMemoryError异常

Java内存溢出异常,通常表现为OutOfMemoryError,涉及Java堆、虚拟机栈、本地方法栈以及方法区的管理。首先,Java堆的设置通过参数-Xms和-Xmx来控制,最小值为-Xms20m,最大值如果不一致,堆会自动扩展。年轻代的大小则通过-Xmn指定。

在遇到内存溢出时,可以设置-XX:+HeapDumpOnOutOfMemoryError,这样当内存溢出时,会自动保存堆转储文件,便于后续分析。在Eclipse中,可通过"debug As"->"open debug dialog"进行配置,然后借助MAT插件进行堆转储文件的分析。

虚拟机栈和本地方法栈的溢出则由-Xss控制,线程的栈大小默认为1M(JDK1.5之后),如果线程过多导致溢出,可以考虑减小-Xmx来增加线程数量,同时减小每个线程的栈容量。栈深度一般1000-2000是安全范围,过深可能会引发StackOverFlow异常。

方法区和运行时常量池的内存管理通过-PermSize和-MaxPermSize来设定,方法区默认占物理内存的1/64。如果内存溢出,可能需要调整这两个参数的大小。

最后,本机直接内存的大小由-XX:MaxDirectMemorySize来控制,如果不设置,其大小默认与-Xmx相同。直接内存溢出通常与大数据处理或内存密集型操作相关,需谨慎调整。

B. java是否有内存泄露和内存溢出

java中的内存溢出和内存泄漏

内存溢出:
对于整个应用程序来说,JVM内存空间,已经没有多余的空间分配给新的对象。所以就发生内存溢出。

内存泄露:
在应用的整个生命周期内,某个对象一直存在,且对象占用的内存空间越来越大,最终导致JVM内存泄露,
比如:缓存的应用,如果不设置上限的话,缓存的容量可能会一直增长。
静态集合引用,如果该集合存放了无数个对象,随着时间的推移也有可能使容量无限制的增长,最终导致JVM内存泄露。

内存泄露,是应用程序中的某个对象长时间的存活,并且占用空间不断增长,最终导致内存泄露。
是对象分配后,长时间的容量增长。

内存溢出,是针对整个应用程序的所有对象的分配空间不足,会造成内存溢出。

内存泄漏
内存泄漏指由于疏忽或错误造成程序未能释放已经不再使用的内存的情况。内存泄漏并非指内存在物理上的消失,而是应用程序分配某段内存后,由于设
计错误,失去了对该段内存的控制,因而造成了内存的浪费。内存泄漏与许多其他问题有着相似的症状,并且通常情况下只能由那些可以获得程序源代码的程序员
可以分析出来。然而,有不少人习惯于把任何不需要的内存使用的增加描述为内存泄漏,即使严格意义上来说这是不准确的。
一般我们常说的内存泄漏
是指堆内存的泄漏。堆内存是指程序从堆中分配的,大小任意的(内存块的大小可以在程序运行期决定),使用完后必须显示释放的内存。应用程序一般使用
malloc,realloc,new等函数从堆中分配到一块内存,使用完后,程序必须负责相应的调用free或delete释放该内存块,否则,这块内
存就不能被再次使用,我们就说这块内存泄漏了。
内存泄漏可以分为4类:
1.
常发性内存泄漏。发生内存泄漏的代码会被多次执行到,每次被执行的时候都会导致一块内存泄漏。
2.
偶发性内存泄漏。发生内存泄漏的代码只有在某些特定环境或操作过程下才会发生。常发性和偶发性是相对的。对于特定的环境,偶发性的也许就变成了常发性的。所以测试环境和测试方法对检测内存泄漏至关重要。
3.
一次性内存泄漏。发生内存泄漏的代码只会被执行一次,或者由于算法上的缺陷,导致总会有一块仅且一块内存发生泄漏。比如,在类的构造函数中分配内存,在析构函数中却没有释放该内存,所以内存泄漏只会发生一次。

4.
隐式内存泄漏。程序在运行过程中不停的分配内存,但是直到结束的时候才释放内存。严格的说这里并没有发生内存泄漏,因为最终程序释放了所有申请的内存。但
是对于一个服务器程序,需要运行几天,几周甚至几个月,不及时释放内存也可能导致最终耗尽系统的所有内存。所以,我们称这类内存泄漏为隐式内存泄漏。

简单点:
内存泄漏就是忘记释放使用完毕的内存,让下次使用有一定风险。

内存溢出就是一定的内存空间不能装下所有的需要存放的数据,造成内存数据溢出。

主要从以下几部分来说明,关于内存和内存泄露、溢出的概念,区分内存泄露和内存溢出;内存的区域划分,了解GC回收机制;重点关注如何去监控和发现内存问题;此外分析出问题还要如何解决内存问题。

下面就开始本篇的内容:

第一部分 概念

众所周知,java中的内存由java虚拟机自己去管理的,他不像C++需要自己去释放。笼统地
去讲,java的内存分配分为两个部分,一个是数据堆,一个是栈。程序在运行的时候一般分配数据堆,把局部的临时的变量都放进去,生命周期和进程有关系。
但是如果程序员声明了static的变量,就直接在栈中运行的,进程销毁了,不一定会销毁static变量。

另外为了保证java内存不会溢出,java中有垃圾回收机制。
System.gc()即垃圾收集机制是指jvm用于释放那些不再使用的对象所占用的内存。java语言并不要求jvm有gc,也没有规定gc如何工作。垃圾收集的目的在于清除不再使用的对象。gc通过确定对象是否被活动对象引用来确定是否收集该对象。

而其中,内存溢出就是你要求分配的java虚拟机内存超出了系统能给你的,系统不能满足需求,于是产生溢出。

内存泄漏是指你向系统申请分配内存进行使用(new),可是使用完了以后却不归还(delete),结果你申请到的那块内存你自己也不能再访
问,该块已分配出来的内存也无法再使用,随着服务器内存的不断消耗,而无法使用的内存越来越多,系统也不能再次将它分配给需要的程序,产生泄露。一直下
去,程序也逐渐无内存使用,就会溢出。

第二部分 原理

JAVA垃圾回收及对内存区划分

在Java虚拟机规范中,提及了如下几种类型的内存空间:

◇ 栈内存(Stack):每个线程私有的。

◇ 堆内存(Heap):所有线程公用的。

◇ 方法区(Method Area):有点像以前常说的“进程代码段”,这里面存放了每个加载类的反射信息、类函数的代码、编译时常量等信息。

◇ 原生方法栈(Native Method Stack):主要用于JNI中的原生代码,平时很少涉及。

而Java的使用的是堆内存,java堆是一个运行时数据区,类的实例(对象)从中分配空间。Java虚拟机(JVM)的堆中储存着正在运行的应用程序所建立的所有对象,“垃圾回收”也是主要是和堆内存(Heap)有关。

垃圾回收的概念就是JAVA虚拟机(JVM)回收那些不再被引用的对象内存的过程。一般我们认为正在被引用的对象状态为“alive”,而没有
被应用或者取不到引用属性的对象状态为“dead”。垃圾回收是一个释放处于”dead”状态的对象的内存的过程。而垃圾回收的规则和算法被动态的作用于
应用运行当中,自动回收。

JVM的垃圾回收器采用的是一种分代(generational )回收策略,用较高的频率对年轻的对象(young
generation)进行扫描和回收,这种叫做minor collection,而对老对象(old generation)的检查回收频率要低很多,称为major
collection。这样就不需要每次GC都将内存中所有对象都检查一遍,这种策略有利于实时观察和回收。

(Sun JVM 1.3
有两种最基本的内存收集方式:一种称为ing或scavenge,将所有仍然生存的对象搬到另外一块内存后,整块内存就可回收。这种方法有效率,但需要有一定的空闲内存,拷贝也有开销。这种方法用于minor
collection。另外一种称为mark-compact,将活着的对象标记出来,然后搬迁到一起连成大块的内存,其他内存就可以回收了。这种方法不需要占用额外的空间,但速度相对慢一些。这种方法用于major collection.


一些对象被创建出来只是拥有短暂的生命周期,比如 iterators 和本地变量。另外一些对象被创建是拥有很长的生命周期,比如持久化对象等。

垃圾回收器的分代策略是把内存区划分为几个代,然后为每个代分配一到多个内存区块。当其中一个代用完了分配给他的内存后,JVM会在分配的内存区内执行一个局部的GC(也可以叫minor
collection)操作,为了回收处于“dead”状态的对象所占用的内存。局部GC通常要比Full GC快很多。

JVM定义了两个代,年轻代(yong generation)(有时称为“nursery”托儿所)和老年代(old generation)。年轻代包括
“Eden space(伊甸园)”和两个“survivor spaces”。虚拟内存初始化的时候会把所有对象都分配到 Eden
space,并且大部分对象也会在该区域被释放。 当进行 minor GC的时候,VM会把剩下的没有释放的对象从Eden space移动到其中一个survivor
spaces当中。此外,VM也会把那些长期存活在survivor spaces 里的对象移动到 老生代的“tenured” space中。当 tenured
generation 被填满后,就会产生Full GC,Full GC会相对比较慢因为回收的内容包括了所有的 live状态的对象。pemanet
generation这个代包括了所有java虚拟机自身使用的相对比较稳定的数据对象,比如类和对象方法等。

关于代的划分,可以从下图中获得一个概况:

第三部分 总结

内存溢出主要是由于代码编写时对某些方法、类应用不合理,或者没有预估到临时对象会占用很大内存量,或者把过多的数据放入JVM缓存,或者性能
压力大导致消息堆积而占用内存,以至于在性能测试时,生成庞大数量的临时对象,GC时没有做出有效回收甚至根本就不能回收,造成内存空间不足,内存溢出。

如果编码之前,对内存使用量进行预估,对放在内存中的数据进行评估,保证有用的信息尽快释放,无用的信息能够被GC回收,这样在一定程度上是可以避免内存溢出问题的。

C. java 程序的内存溢出问题如何解决

Java程序的内存溢出问题可以通过以下几种方式来解决:

1. 增加JVM堆内存大小:可以通过在启动JVM时设置-Xmx和-Xms参数来调整堆内存的大小。例如,"-Xms256m -Xmx1024m"表示最小堆内存为256MB,最大堆内存为1024MB。

2. 优化代码:检查代码中是否存在内存泄漏或者不必要的大对象创建。例如,使用完的大对象没有被及时回收,或者存在大量的临时对象没有被释放等。

3. 使用内存分析工具:可以使用如VisualVM、MAT等工具来分析程序的内存使用情况,找出内存使用的热点,然后针对这些热点进行优化。

4. 使用缓存:对于一些需要大量计算的数据,可以考虑使用缓存来减少内存的使用。

5. 使用垃圾回收器:选择合适的垃圾回收器也可以帮助减少内存的使用。例如,对于需要低延迟的应用,可以选择G1垃圾回收器;对于需要高吞吐量的应用,可以选择并行垃圾回收器。

6. 分布式处理:如果单个JVM实例无法满足内存需求,可以考虑将程序部署到多个JVM实例上,通过分布式处理来解决内存溢出问题。

阅读全文

与java内存泄露内存溢出相关的资料

热点内容
php如何建站 浏览:642
苹果手机桌面的app怎么隐藏了 浏览:283
建行生活APP的五折券怎么用 浏览:963
云服务器时钟 浏览:117
就无命令 浏览:658
安卓系统微信怎么找回好友视频 浏览:689
ug90pdf 浏览:397
纯正的溯源码燕碎多少钱一克 浏览:105
命令控制行有什么用 浏览:440
便携式数控切割机编程 浏览:697
androidtcp接收 浏览:40
linux进程数据共享 浏览:669
android应用搜索 浏览:804
安卓压缩视频app 浏览:461
51单片机fats文件系统 浏览:513
登录app一直提示服务器繁忙是什么 浏览:791
怎么架设传奇游戏服务器 浏览:373
网站如何加密网页 浏览:965
怎么解压文件在手机上 浏览:172
绿地回收App怎么登陆 浏览:656