当前位置:首页 » 编程语言 » java代码内存

java代码内存

发布时间: 2022-05-19 00:39:32

1. java程序内存溢出一般什么原因

JVM内存设置小了 或者一次性读的数据过大 例如list vertor

一、内存溢出类型

1、java.lang.OutOfMemoryError: PermGen space

JVM管理两种类型的内存,堆和非堆。堆是给开发人员用的上面说的就是,是在JVM启动时创建;非堆是留给JVM自己用的,用来存放类的信息的。它和堆不同,运行期内GC不会释放空间。如果web
app用了大量的第三方jar或者应用有太多的class文件而恰好MaxPermSize设置较小,超出了也会导致这块内存的占用过多造成溢出,或者tomcat热部署时侯不会清理前面加载的环境,只会将context更改为新部署的,非堆存的内容就会越来越多。

PermGen space的全称是Permanent Generation
space,是指内存的永久保存区域,这块内存主要是被JVM存放Class和Meta信息的,Class在被Loader时就会被放到PermGen
space中,它和存放类实例(Instance)的Heap区域不同,GC(Garbage Collection)不会在主程序运行期对PermGen
space进行清理,所以如果你的应用中有很CLASS的话,就很可能出现PermGen space错误,这种错误常见在web服务器对JSP进行pre
compile的时候。如果你的WEB APP下都用了大量的第三方jar, 其大小超过了jvm默认的大小(4M)那么就会产生此错误信息了。

一个最佳的配置例子:(经过本人验证,自从用此配置之后,再未出现过tomcat死掉的情况)

set JAVA_OPTS=-Xms800m -Xmx800m -XX:PermSize=128M -XX:MaxNewSize=256m
-XX:MaxPermSize=256m

2、java.lang.OutOfMemoryError: Java heap space

第一种情况是个补充,主要存在问题就是出现在这个情况中。其默认空间(即-Xms)是物理内存的1/64,最大空间(-Xmx)是物理内存的1/4。如果内存剩余不到40%,JVM就会增大堆到Xmx设置的值,内存剩余超过70%,JVM就会减小堆到Xms设置的值。所以服务器的Xmx和Xms设置一般应该设置相同避免每次GC后都要调整虚拟机堆的大小。假设物理内存无限大,那么JVM内存的最大值跟操作系统有关,一般32位机是1.5g到3g之间,而64位的就不会有限制了。

注意:如果Xms超过了Xmx值,或者堆最大值和非堆最大值的总和超过了物理内存或者操作系统的最大限制都会引起服务器启动不起来。

垃圾回收GC的角色

JVM调用GC的频度还是很高的,主要两种情况下进行垃圾回收:

当应用程序线程空闲;另一个是java内存堆不足时,会不断调用GC,若连续回收都解决不了内存堆不足的问题时,就会报out of
memory错误。因为这个异常根据系统运行环境决定,所以无法预期它何时出现。

根据GC的机制,程序的运行会引起系统运行环境的变化,增加GC的触发机会。

为了避免这些问题,程序的设计和编写就应避免垃圾对象的内存占用和GC的开销。显示调用System.GC()只能建议JVM需要在内存中对垃圾对象进行回收,但不是必须马上回收,

一个是并不能解决内存资源耗空的局面,另外也会增加GC的消耗。

二、JVM内存区域组成

简单的说java中的堆和栈

java把内存分两种:一种是栈内存,另一种是堆内存

1。在函数中定义的基本类型变量和对象的引用变量都在函数的栈内存中分配;

2。堆内存用来存放由new创建的对象和数组

在函数(代码块)中定义一个变量时,java就在栈中为这个变量分配内存空间,当超过变量的作用域后,java会自动释放掉为该变量所分配的内存空间;在堆中分配的内存由java虚拟机的自动垃圾回收器来管理

堆的优势是可以动态分配内存大小,生存期也不必事先告诉编译器,因为它是在运行时动态分配内存的。缺点就是要在运行时动态分配内存,存取速度较慢;

栈的优势是存取速度比堆要快,缺点是存在栈中的数据大小与生存期必须是确定的无灵活性。

java堆分为三个区:New、Old和Permanent

GC有两个线程:

新创建的对象被分配到New区,当该区被填满时会被GC辅助线程移到Old区,当Old区也填满了会触发GC主线程遍历堆内存里的所有对象。Old区的大小等于Xmx减去-Xmn

java栈存放

栈调整:参数有+UseDefaultStackSize -Xss256K,表示每个线程可申请256k的栈空间

每个线程都有他自己的Stack

三、JVM如何设置虚拟内存

提示:在JVM中如果98%的时间是用于GC且可用的Heap size 不足2%的时候将抛出此异常信息。

提示:Heap Size 最大不要超过可用物理内存的80%,一般的要将-Xms和-Xmx选项设置为相同,而-Xmn为1/4的-Xmx值。

提示:JVM初始分配的内存由-Xms指定,默认是物理内存的1/64;JVM最大分配的内存由-Xmx指定,默认是物理内存的1/4。

默认空余堆内存小于40%时,JVM就会增大堆直到-Xmx的最大限制;空余堆内存大于70%时,JVM会减少堆直到-Xms的最小限制。因此服务器一般设置-Xms、-Xmx相等以避免在每次GC
后调整堆的大小。

提示:假设物理内存无限大的话,JVM内存的最大值跟操作系统有很大的关系。

简单的说就32位处理器虽然可控内存空间有4GB,但是具体的操作系统会给一个限制,

这个限制一般是2GB-3GB(一般来说Windows系统下为1.5G-2G,Linux系统下为2G-3G),而64bit以上的处理器就不会有限制了

提示:注意:如果Xms超过了Xmx值,或者堆最大值和非堆最大值的总和超过了物理内存或者操作系统的最大限制都会引起服务器启动不起来。

提示:设置NewSize、MaxNewSize相等,"new"的大小最好不要大于"old"的一半,原因是old区如果不够大会频繁的触发"主" GC
,大大降低了性能

JVM使用-XX:PermSize设置非堆内存初始值,默认是物理内存的1/64;

由XX:MaxPermSize设置最大非堆内存的大小,默认是物理内存的1/4。

解决方法:手动设置Heap size

修改TOMCAT_HOME/bin/catalina.bat

在“echo "Using CATALINA_BASE: $CATALINA_BASE"”上面加入以下行:

JAVA_OPTS="-server -Xms800m -Xmx800m -XX:MaxNewSize=256m"

四、性能检查工具使用

定位内存泄漏:

JProfiler工具主要用于检查和跟踪系统(限于Java开发的)的性能。JProfiler可以通过时时的监控系统的内存使用情况,随时监视垃圾回收,线程运行状况等手段,从而很好的监视JVM运行情况及其性能。

1. 应用服务器内存长期不合理占用,内存经常处于高位占用,很难回收到低位;

2. 应用服务器极为不稳定,几乎每两天重新启动一次,有时甚至每天重新启动一次;

3. 应用服务器经常做Full GC(Garbage Collection),而且时间很长,大约需要30-40秒,应用服务器在做Full
GC的时候是不响应客户的交易请求的,非常影响系统性能。

因为开发环境和产品环境会有不同,导致该问题发生有时会在产品环境中发生,通常可以使用工具跟踪系统的内存使用情况,在有些个别情况下或许某个时刻确实是使用了大量内存导致out
of memory,这时应继续跟踪看接下来是否会有下降,

如果一直居高不下这肯定就因为程序的原因导致内存泄漏。

五、不健壮代码的特征及解决办法

1、尽早释放无用对象的引用。好的办法是使用临时变量的时候,让引用变量在退出活动域后,自动设置为null,暗示垃圾收集器来收集该对象,防止发生内存泄露。

对于仍然有指针指向的实例,jvm就不会回收该资源,因为垃圾回收会将值为null的对象作为垃圾,提高GC回收机制效率;

2、我们的程序里不可避免大量使用字符串处理,避免使用String,应大量使用StringBuffer,每一个String对象都得独立占用内存一块区域;

String str = "aaa";

String str2 = "bbb";

String str3 = str + str2;//假如执行此次之后str
,str2以后再不被调用,那它就会被放在内存中等待Java的gc去回收,程序内过多的出现这样的情况就会报上面的那个错误,建议在使用字符串时能使用StringBuffer就不要用String,这样可以省不少开销;

3、尽量少用静态变量,因为静态变量是全局的,GC不会回收的;

4、避免集中创建对象尤其是大对象,JVM会突然需要大量内存,这时必然会触发GC优化系统内存环境;显示的声明数组空间,而且申请数量还极大。

这是一个案例想定供大家警戒

使用jspsmartUpload作文件上传,运行过程中经常出现java.outofMemoryError的错误,

检查之后发现问题:组件里的代码

m_totalBytes = m_request.getContentLength();

m_binArray = new byte[m_totalBytes];

问题原因是totalBytes这个变量得到的数极大,导致该数组分配了很多内存空间,而且该数组不能及时释放。解决办法只能换一种更合适的办法,至少是不会引发outofMemoryError的方式解决。参考:http://bbs.xml.org.cn/blog/more.asp?name=hongrui&id=3747

5、尽量运用对象池技术以提高系统性能;生命周期长的对象拥有生命周期短的对象时容易引发内存泄漏,例如大集合对象拥有大数据量的业务对象的时候,可以考虑分块进行处理,然后解决一块释放一块的策略。

6、不要在经常调用的方法中创建对象,尤其是忌讳在循环中创建对象。可以适当的使用hashtable,vector
创建一组对象容器,然后从容器中去取那些对象,而不用每次new之后又丢弃

7、一般都是发生在开启大型文件或跟数据库一次拿了太多的数据,造成 Out Of Memory Error
的状况,这时就大概要计算一下数据量的最大值是多少,并且设定所需最小及最大的内存空间值。

2. 为什么这么一小段java代码会使用那么多内存

JVM调用GC的频度还是很高的,主要两种情况下进行垃圾回收:
当应用程序线程空闲;另一个是java内存堆不足时,会不断调用GC,若连续回收都解决不了内存堆不足的问题时,就会报out of memory错误。因为这个异常根据系统运行环境决定,所以无法预期它何时出现。
根据GC的机制,程序的运行会引起系统运行环境的变化,增加GC的触发机会。
为了避免这些问题,程序的设计和编写就应避免垃圾对象的内存占用和GC的开销。显示调用System.GC()只能建议JVM需要在内存中对垃圾对象进行回收,但不是必须马上回收,
一个是并不能解决内存资源耗空的局面,另外也会增加GC的消耗。

3. 请教:为什么这么一小段java代码会使用那么多内存

一般出现这种情况是程序还有线程没有结束。处理方法有二:1、记录下自己开启的线程(比如定时器),并手动destroy。2、监听窗口的关闭事件,执行强制退出。代码示例如下:myWindow.addWindowListener(new WindowAdapter() { @Override public void windowClosed(WindowEvent e) { System.exit(0);// 强制退出 }});

4. 如何计算一个Java程序运行占用多少内存

可以用 system(命令) 调用 DOS/Windows 命令 获取 正在使用多少 内存 (memory).
命令例子:
wmic process where name="cmd.exe" get WorkingSetSize
这里 "cmd.exe" 你可替换成 你的程序 名字。
你也可以用你的程序 进程 PID 号数 调用, 命令是:
wmic process where processid=6884 get WorkingSetSize
这里6884你可替换成 你的程序 进程 PID。
输出有2行,第二行是占用内存字节数:
WorkingSetSize
4616192
c/c++ 语言 :
system("wmic process where processid=6884 get WorkingSetSize");
system("wmic process where name=\"cmd.exe\" get WorkingSetSize");
用程序名调用时,若有多个同名程序在运行,输出的 内存数 将分行输出出来。

5. 怎么查看java代码是否内存泄露

第一阶段 通过jdk的GC输出进行测试
可以在 JAVA_OPTS增加以下参数打开jdk的GC输出日志:
-verbose:gc -XX:+PrintGCDetails -XX:+HeapDumpOnOutOfMemoryError
打开输出日志,jdk会在每一次的垃圾回收时打印相关日志
第二阶段 通过jmap命令
jmap命令可以获得运行中的jvm的堆的快照,从而可以离线分析堆,以检查内存泄漏,检查一些严重影响性能的大对象的创建,检查系统中什么对象最多,各种对象所占内存的大小等等
第三阶段 通过Eclipse Memory Analyzer 分析工具来分析
Eclipse Memory Analyzer是一种快速的,功能丰富的Java堆分析工具,以下简称MAT,可以帮助查找内存泄露,并减少内存消耗。 这个工具可以对由堆转储产生的数以亿计的对象进行分析,一旦堆转储被解析,可以在打开他的一瞬间,立即得到保留大小的单一对象,提取记录详细的信息,查看为什么这些对象对象资料没有被释放掉。使用这些功能的报告,可以对这些对象进行跟踪,找到内存泄露嫌疑人,也可以得到系统的性能指数,帮助优化系统。

6. 如何看一段JAVA代码耗了多少内存

使用java自带的性能分析工具jvisualvm , 可以方便的查看内存, 对象, 线程等多种信息.

win+R然后输入jvisualvm回车即可

效果如下图

7. 谁能解释下这段java代码运行时,内存是怎么变化的。

我看还是我来回答吧。 注意了!!Java大虾到!!

首先啊,你要知道Java方法调用都是传值的,其次要知道基本类型和对象的区别。
我们来一个个分析你就明白了。
int n=1;
String s="abc";
supper sp=new supper();
这三个量中有一个基本类型,两个对象对吧?那你知到他们有什么区别么?
我来简单的说一下吧。
基本类型很简单,比如整型n就是四字节空间,那这个n存在哪里呢?
存在栈里面(因为他是局部变量)。
由于是传值,那么他就把n的值传过去了,那边的形参也是个局部变量,也存在栈里面(f1调用栈),所以本质上main的n1和f1中的n1是俩n1,所以你改变fi中的n1后mian里面的n1显然不会变。

对象也是传值!!不要说对象是传引用的,如果你老师这样叫你那只能说他不真正理解Java内存结构。
对象是什么?或者说s和sp到底是个什么?
我跟你说,他们首先是个局部变量,存在哪里?和n一样存在main栈里。占多大空间?4个字节!!
撒意思?意思就是所谓对象,实质上就是一指针变量!(Java语法上没指针,但Java实现上有的)
指针的内容或说指针指向哪里?指向堆中的两个对象空间。至于撒是对象空间,我就不细说了,与本问题无关。
所以对象s和sp有两层含义,一是指两个局部变量,而是指这两变量对应的对象空间。

再回到传值的问题上。
调f2、f3同样是传值!!但因为s、sp本身就一指针,所以传的值就是俩对象的内存地址。
好吧,继续分析为什么s不变而sp变。
s不变的原因归结于字符串这个类的特性。不知道你老师告诉过你没有,字符串是不可变的!不知道也没关系,我们看看s的处理过程:
s+="def"; 等价于s = s+"def"
s+"def"怎么处理的你知道么?是把def放入s对象空间中么?不是的。
过程是这样滴:先算出s的长度和def的长度,然后在堆里面开辟一对象空间,之后把s、def都拷进去。而s = s+"def"撒意思呢?那就是考进去之后再把这个新开辟对象的地址放入变量s中去(说过了s是f2的一局部指针类型的变量)。
看看,看看!
main的s把值(对象空间地址)给了f2的s,而你“一不小心”通过s = s+"def"把s中存储的值换成一个新对象的值了。那么f2的s和main的s还指向同一个对象么???不是的。既然不是的,main的s当然不会变?

现在在看看sp
同里,main的sp把自己存的地址拷贝给f3的sp,而你呢?显然没有重新给sp赋值,这也就意味着虽然俩sp是两个局部变量,但这两个变量指向的对象空间是一样滴。
因此,你通过f3的sp操作其成员num,当然会影响main的sp了。

明白了??不明白?我都快累死了你还不明白?去死!
:)

8. 请问用Java代码,怎样测试一段程序占用了多少内存

你可以先用内存监控工具,进行监控,看看这个功能到底用多少内存。如果不多,其实都不需要实现你说的代码监控的。如果你要使用代码监控,你可是使用Runtime类的几个属性,MaxMemory、FreeMemory、TotalMemory。然后实现个线程,在下载pdf功能前开启线程,然后完毕时关闭线程,如果内存即将溢出(设定个阈值,比如说15%),就报错,跳转到错误页面。

热点内容
c语言编译后图片 发布:2025-05-15 13:51:57 浏览:792
没有被调用的函数会参与编译吗 发布:2025-05-15 13:42:51 浏览:260
在计算机中ftp的中文 发布:2025-05-15 13:41:07 浏览:1000
国网校招要网签密码和账号干什么 发布:2025-05-15 13:40:25 浏览:179
java分 发布:2025-05-15 13:34:36 浏览:846
如何下载卡巴斯基安卓版 发布:2025-05-15 13:34:36 浏览:480
排序函数c语言 发布:2025-05-15 13:06:28 浏览:6
韩服lol挂机脚本 发布:2025-05-15 12:42:56 浏览:462
监控存储服务器如何调试 发布:2025-05-15 12:36:30 浏览:219
一万级净化车间有哪些配置 发布:2025-05-15 12:16:41 浏览:98