内存泄露和内存溢出


1、 内存泄露程序员

   内存泄漏指因为疏忽或错误形成程序未能释放已经再也不使用的内存的状况。内存泄漏并不是指内存在物理上的消失,而是应用程序分配某段内存后,因为设计错误,失去了对该段内存的控制,于是形成了内存的浪费。内存泄漏与许多其余问题有着类似的症状,而且一般状况下只能由那些能够得到程序源代码的程序员才能够分析出来。然而,有很多人习惯于把任何不须要的内存使用的增长描述为内存泄漏,即便严格意义上来讲这是不许确的。
  通常咱们常说的内存泄漏是指堆内存的泄漏。堆内存是指程序从堆中分配的,大小任意的(内存块的大小能够在程序运行期决定),使用完后必须显示释放的内存。应用程序通常使用malloc,realloc,new等函数从堆中分配到一块内存,使用完后,程序必须负责相应的调用free或delete释放该内存块,不然,这块内存就不能被再次使用,咱们就说这块内存泄漏了。
  内存泄漏能够分为4类:
  1. 常发性内存泄漏。发生内存泄漏的代码会被屡次执行到,每次被执行的时候都会致使一块内存泄漏。
  2. 偶发性内存泄漏。发生内存泄漏的代码只有在某些特定环境或操做过程下才会发生。常发性和偶发性是相对的。对于特定的环境,偶发性的也许就变成了常发性的。因此测试环境和测试方法对检测内存泄漏相当重要。
  3. 一次性内存泄漏。发生内存泄漏的代码只会被执行一次,或者因为算法上的缺陷,致使总会有一块仅且一块内存发生泄漏。好比,在一个Singleton类的构造函数中分配内存,在析构函数中却没有释放该内存。而Singleton类只存在一个实例,因此内存泄漏只会发生一次。
  4. 隐式内存泄漏。程序在运行过程当中不停的分配内存,可是直到结束的时候才释放内存。严格的说这里并无发生内存泄漏,由于最终程序释放了全部申请的内存。可是对于一个服务器程序,须要运行几天,几周甚至几个月,不及时释放内存也可能致使最终耗尽系统的全部内存。因此,咱们称这类内存泄漏为隐式内存泄漏。                        算法

   内存泄漏会由于减小可用内存的数量从而下降计算机的性能。最终,在最糟糕的状况下,过多的可用内存被分配掉致使所有或部分设备中止正常工做,或者应用程序崩溃。
  内存泄漏可能不严重,甚至可以被常规的手段检测出来。在现代操做系统中,一个应用程序使用的常规内存在程序终止时被释放。这表示一个短暂运行的应用程序中的内存泄漏不会致使严重后果。
  在如下状况,内存泄漏致使较严重的后果:
  * 程序运行后置之不理,而且随着时间的流失消耗愈来愈多的内存(好比服务器上的后台任务,尤为是嵌入式系统中的后台任务,这些任务可能被运行后不少年内都置之不理);
  * 新的内存被频繁地分配,好比当显示电脑游戏或动画视频画面时;
  * 程序可以请求未被释放的内存(好比共享内存),甚至是在程序终止的时候;
  * 泄漏在操做系统内部发生;
  * 泄漏在系统关键驱动中发生;
  * 内存很是有限,好比在嵌入式系统或便携设备中;
  * 当运行于一个终止时内存并不自动释放的操做系统(好比AmigaOS)之上,并且一旦丢失只能经过重启来恢复。数据库

 

2、内存溢出编程

   内存溢出已是软件开发历史上存在了近40年的“老大难”问题,象在“红色代码”病毒事件中表现的那样,它已经成为黑客攻击企业网络的“罪魁祸首”。 如在一个域中输入的数据超过了它的要求就会引起数据溢出问题,多余的数据就能够做为指令在计算机上运行。据有关安全小组称,操做系统中超过50%的安全漏洞都是由内存溢出引发的,其中大多数和微软的技术有关。
  为了便于理解,咱们不妨打个比方。缓冲区溢出比如是将十磅的糖放进一个只能装五磅的容器里。一旦该容器放满了,余下的部分就溢出在柜台和地板上,弄得一团糟。因为计算机程序的编写者写了一些编码,可是这些编码没有对目的区域或缓冲区——五磅的容器——作适当的检查,看它们是否够大,可否彻底装入新的内容——十磅的糖,结果可能形成缓冲区溢出的产生。若是打算被放进新地方的数据不适合,溢获得处都是,该数据也会制造不少麻烦。可是,若是缓冲区仅仅溢出,这只是一个问题。到此时为止,它尚未破坏性。当糖溢出时,柜台被盖住。能够把糖擦掉或用吸尘器吸走,还柜台原本面貌。与之相对的是,当缓冲区溢出时,过剩的信息覆盖的是计算机内存中之前的内容。除非这些被覆盖的内容被保存或可以恢复,不然就会永远丢失。
  在丢失的信息里有可以被程序调用的子程序的列表信息,直到缓冲区溢出发生。另外,给那些子程序的信息——参数——也丢失了。这意味着程序不能获得足够的信息从子程序返回,以完成它的任务。就像一我的步行穿过沙漠。若是他依赖于他的足迹走回头路,当沙暴来袭抹去了这些痕迹时,他将迷失在沙漠中。这个问题比程序仅仅迷失方向严重多了。入侵者用精心编写的入侵代码(一种恶意程序)使缓冲区溢出,而后告诉程序依据预设的方法处理缓冲区,而且执行。此时的程序已经彻底被入侵者操纵了。
  入侵者常常改编现有的应用程序运行不一样的程序。例如,一个入侵者能启动一个新的程序,发送秘密文件(支票本记录,口令文件,或财产清单)给入侵者的电子邮件。这就好像不只仅是沙暴吹了脚印,并且后来者也会踩出新的脚印,将咱们的迷路者领向不一样的地方,他本身一无所知的地方。
  缓冲区溢出的处理
  你屋子里的门和窗户越少,入侵者进入的方式就越少……
  因为缓冲区溢出是一个编程问题,因此只能经过修复被破坏的程序的代码而解决问题。若是你没有源代码,从上面“堆栈溢出攻击”的原理能够看出,要防止此类攻击,咱们能够:
  一、开放程序时仔细检查溢出状况,不容许数据溢出缓冲区。因为编程和编程语言的缘由,这很是困难,并且不适合大量已经在使用的程序;
  二、使用检查堆栈溢出的编译器或者在程序中加入某些记号,以便程序运行时确认禁止黑客有意形成的溢出。问题是没法针对已有程序,对新程序来说,须要修改编译器;
  三、常常检查你的操做系统和应用程序提供商的站点,一旦发现他们提供的补丁程序,就立刻下载而且应用在系统上,这是最好的方法。可是系统管理员总要比攻击者慢一步,若是这个有问题的软件是可选的,甚至是临时的,把它从你的系统中删除。举另一个例子,你屋子里的门和窗户越少,入侵者进入的方式就越少。tomcat




内存溢出  :机器的配置,服务器的问题,安全


很大一方面多是链接池
还有就可能没有处理代码中的内存泄露
服务器

要说就是项目的问题
内存溢出主要问题
1.数据库没有关毕,时间长了就会数据库没有关闭致使数据溢出
2.程序优化问题,若是一个程序没有优化好的话就会致使数据过多溢出

3.再就是若是数据库的连接用了“链接池”的问题,数据库的链接次数过多致使“数据溢出”网络

tomcat默承认以使用的内存为128MB,在较大型的应用项目中,这点内存是不够的,须要调大。

  Windows下,在文件/bin/catalina.bat,Unix下,在文件/bin/catalina.sh的前面,增长以下设置:

  JAVA_OPTS='-Xms【初始化内存大小】 -Xmx【可使用的最大内存】'

  如:

  JAVA_OPTS='-Xms256m -Xmx512m'

  表示初始化内存为256MB,可使用的最大内存为512MB。


加大tomcat链接数

在tomcat配置文件server.xml中的<Connector ... />配置中,和链接数相关的参数有:
minProcessors:最小空闲链接线程数,用于提升系统处理性能,默认值为10
maxProcessors:最大链接线程数,即:并发处理的最大请求数,默认值为75
acceptCount:容许的最大链接数,应大于等于maxProcessors,默认值为100
enableLookups:是否反查域名,取值为:true或false。为了提升处理能力,应设置为false
connectionTimeout:网络链接超时,单位:毫秒。设置为0表示永不超时,这样设置有隐患的。一般可设置为30000毫秒
并发


内存溢出  

2010-11-23 22:09:10|  分类: J2SE|举报|字号 订阅编程语言

    通俗理解就是内存不够,一般在运行大型软件或游戏时,软件或游戏所须要的内存远远超出了你主机内安装的内存所承受大小,就叫内存溢出。此时软件或游戏就运行不了,系统会提示内存溢出,有时候会自动关闭软件,重启电脑或者软件后释放掉一部份内存又能够正常运行该软件或游戏一段时间。

含义

  内存溢出已是软件开发历史上存在了近40年的“老大难”问题,像在“红色代码”病毒事件中表现的那样,它已经成为黑客攻击企业网络的“罪魁祸首”。 如在一个域中输入的数据超过了它的要求就会引起数据溢出问题,多余的数据就能够做为指令在计算机上运行。据有关安全小组称,操做系统中超过50%的安全漏洞都是由内存溢出引发的,其中大多数与微软的技术有关。
  为了便于理解,咱们不妨打个比方。缓冲区溢出比如是将十磅的糖放进一个只能装五磅的容器里。一旦该容器放满了,余下的部分就溢出在柜台和地板上,弄得一团糟。因为计算机程序的编写者写了一些编码,可是这些编码没有对目的区域或缓冲区——五磅的容器——作适当的检查,看它们是否够大,可否彻底装入新的内容——十磅的糖,结果可能形成缓冲区溢出的产生。若是打算被放进新地方的数据不适合,溢获得处都是,该数据也会制造不少麻烦。可是,若是缓冲区仅仅溢出,这只是一个问题。到此时为止,它尚未破坏性。当糖溢出时,柜台被盖住。能够把糖擦掉或用吸尘器吸走,还柜台原本面貌。与之相对的是,当缓冲区溢出时,过剩的信息覆盖的是计算机内存中之前的内容。除非这些被覆盖的内容被保存或可以恢复,不然就会永远丢失。
  在丢失的信息里有可以被程序调用的子程序的列表信息,直到缓冲区溢出发生。另外,给那些子程序的信息——参数——也丢失了。这意味着程序不能获得足够的信息从子程序返回,以完成它的任务。就像一我的步行穿过沙漠。若是他依赖于他的足迹走回头路,当沙暴来袭抹去了这些痕迹时,他将迷失在沙漠中。这个问题比程序仅仅迷失方向严重多了。入侵者用精心编写的入侵代码(一种恶意程序)使缓冲区溢出,而后告诉程序依据预设的方法处理缓冲区,而且执行。此时的程序已经彻底被入侵者操纵了。
  入侵者常常改编现有的应用程序运行不一样的程序。例如,一个入侵者能启动一个新的程序,发送秘密文件(支票本记录,口令文件,或财产清单)给入侵者的电子邮件。这就好像不只仅是沙暴吹了脚印,并且后来者也会踩出新的脚印,将咱们的迷路者领向不一样的地方,他本身一无所知的地方。

 
缓冲区溢出的处理

  你屋子里的门和窗户越少,入侵者进入的方式就越少……
  因为缓冲区溢出是一个编程问题,因此只能经过修复被破坏的程序的代码而解决问题。若是你没有源代码,从上面“堆栈溢出攻击”的原理能够看出,要防止此类攻击,咱们能够:
  一、开放程序时仔细检查溢出状况,不容许数据溢出缓冲区。因为编程和编程语言的缘由,这很是困难,并且不适合大量已经在使用的程序;
  二、使用检查堆栈溢出的编译器或者在程序中加入某些记号,以便程序运行时确认禁止黑客有意形成的溢出。问题是没法针对已有程序,对新程序来说,须要修改编译器;
  三、常常检查你的操做系统和应用程序提供商的站点,一旦发现他们提供的补丁程序,就立刻下载而且应用在系统上,这是最好的方法。可是系统管理员总要比攻击者慢一步,若是这个有问题的软件是可选的,甚至是临时的,把它从你的系统中删除。举另一个例子,你屋子里的门和窗户越少,入侵者进入的方式就越少。

 
问题的提出

  内存溢出与数据库锁表的问题,能够说是开发人员的噩梦,通常的程序异常,老是能够知道在何时或是在什么操做步骤上出现了异常,并且根据堆栈信息也很容易定位到程序中是某处出现了问题。内存溢出与锁表则否则,通常现象是操做通常时间后系统愈来愈慢,直到死机,但并不能明确是在什么操做上出现的,发生的时间点也没有规律,查看日志或查看数据库也不能定位出问题的代码。
  更严重的是内存溢出与数据库锁表在系统开发和单元测试阶段并不容易被发现,当系统正式上线通常时间后,操做的并发量上来了,数据也积累了一些,系统就容易出现内存溢出或是锁表的现象,而此时系统又不能随意停机或重启,为修正BUG带来很大的困难。
  本文以笔者开发和支持的多个项目为例,与你们分享在开发过程当中遇到的Java内存溢出和数据库锁表的检测和处理解决过程。

 
内存溢出的分析

  内存溢出是指应用系统中存在没法回收的内存或使用的内存过多,最终使得程序运行要用到的内存大于虚拟机能提供的最大内存。为了解决Java中内存溢出问题,咱们首先必须了解Java是如何管理内存的。Java的内存管理就是对象的分配和释放问题。在Java中,内存的分配是由程序完成的,而内存的释放是由垃圾收集器(GarbageCollection,GC)完成的,程序员不须要经过调用GC函数来释放内存,由于不一样的JVM实现者可能使用不一样的算法管理GC,有的是内存使用到达必定程度时,GC才开始工做,也有定时执行的,有的是中断式执行GC。但GC只能回收无用而且再也不被其它对象引用的那些对象所占用的空间。Java的内存垃圾回收机制是从程序的主要运行对象开始检查引用链,当遍历一遍后发现没有被引用的孤立对象就做为垃圾回收。
  引发内存溢出的缘由有不少种,常见的有如下几种:
  ? 内存中加载的数据量过于庞大,如一次从数据库取出过多数据;
  ? 集合类中有对对象的引用,使用完后未清空,使得JVM不能回收;
  ? 代码中存在死循环或循环产生过多重复的对象实体;
  ? 使用的第三方软件中的BUG;
  ? 启动参数内存值设定的太小;

内存溢出的解决

  内存溢出虽然很棘手,但也有相应的解决办法,能够按照从易到难,一步步的解决。   第一步,就是修改JVM启动参数,直接增长内存。这一点看上去彷佛很简单,但很容易被忽略。JVM默承认以使用的内存为64M,Tomcat默承认以使用的内存为128MB,对于稍复杂一点的系统就会不够用。在某项目中,就由于启动参数使用的默认值,常常报“OutOfMemory”错误。所以,-Xms,-Xmx参数必定不要忘记加。   第二步,检查错误日志,查看“OutOfMemory”错误前是否有其它异常或错误。在一个项目中,使用两个数据库链接,其中专用于发送短信的数据库链接使用DBCP链接池管理,用户为不将短信发出,有意将数据库链接用户名改错,使得日志中有许多数据库链接异常的日志,一段时间后,就出现“OutOfMemory”错误。经分析,这是因为DBCP链接池BUG引发的,数据库链接不上后,没有将链接释放,最终使得DBCP报“OutOfMemory”错误。通过修改正确数据库链接参数后,就没有再出现内存溢出的错误。   查看日志对于分析内存溢出是很是重要的,经过仔细查看日志,分析内存溢出前作过哪些操做,能够大体定位有问题的模块。   第三步,安排有经验的编程人员对代码进行走查和分析,找出可能发生内存溢出的位置。重点排查如下几点:   ? 检查代码中是否有死循环或递归调用。   ? 检查是否有大循环重复产生新对象实体。   ? 检查对数据库查询中,是否有一次得到所有数据的查询。通常来讲,若是一次取十万条记录到内存,就可能引发内存溢出。这个问题比较隐蔽,在上线前,数据库中数据较少,不容易出问题,上线后,数据库中数据多了,一次查询就有可能引发内存溢出。所以对于数据库查询尽可能采用分页的方式查询。   ? 检查List、MAP等集合对象是否有使用完后,未清除的问题。List、MAP等集合对象会始终存有对对象的引用,使得这些对象不能被GC回收。   第四步,使用内存查看工具动态查看内存使用状况。某个项目上线后,每次系统启动两天后,就会出现内存溢出的错误。这种状况通常是代码中出现了缓慢的内存泄漏,用上面三个步骤解决不了,这就须要使用内存查看工具了。   内存查看工具备许多,比较有名的有:Optimizeit Profiler、JProbeProfiler、JinSight和Java1.5的Jconsole等。它们的基本工做原理大同小异,都是监测Java程序运行时全部对象的申请、释放等动做,将内存管理的全部信息进行统计、分析、可视化。开发人员能够根据这些信息判断程序是否有内存泄漏问题。通常来讲,一个正常的系统在其启动完成后其内存的占用量是基本稳定的,而不该该是无限制的增加的。持续地观察系统运行时使用的内存的大小,能够看到在内存使用监控窗口中是基本规则的锯齿形的图线,若是内存的大小持续地增加,则说明系统存在内存泄漏问题。经过间隔一段时间取一次内存快照,而后对内存快照中对象的使用与引用等信息进行比对与分析,能够找出是哪一个类的对象在泄漏。   经过以上四个步骤的分析与处理,基本能处理内存溢出的问题。固然,在这些过程当中也须要至关的经验与敏感度,须要在实际的开发与调试过程当中不断积累。
相关文章
相关标签/搜索