C++编程中如何防止内存溢出问题? C++内存溢出及代码优化问题

作者&投稿:贸桂 (若有异议请与网页底部的电邮联系)
1.
良好的编程习惯是预防内存漏洞的根本2.
正确申请和释放内存空间。3.
记得在每个可能的出口检查指针
导致内存溢出问题的原因有很多,比如:(1)使用非类型安全
(non-type-safe)的语言如C/C++等。
(2)以不可靠的方式存取或者复制内存缓冲区。
(3)编译器设置的内存缓冲区太靠近关键数据结构。
下面来分析这些因素:1.
内存溢出问题是C语言或者C++语言所固有的缺陷,它们既不检查数组边界,又不检查类型可靠性
(type-safety)
。众所周知,用C/C++语言开发的程序由于目标代码非常接近机器内核,因而能够直接访问内存和寄存器,这种特性大大提升了C/C++语言代码的性能。只要合理编码,
C/C++应用程序在执行效率上必然优于其它高级语言。然而,
C/C++语言导致内存溢出问题的可能性也要大许多。其他语言也存在内容溢出问题,但它往往不是程序员的失误,而是应用程序的运行时环境出错所致。2.
当应用程序读取用户(也可能是恶意攻击者)数据,试图复制到应用程序开辟的内存缓冲区中,却无法保证缓冲区的空间足够时(换言之,假设代码申请了N字节大小的内存缓冲区,随后又向其中复制超过N字节的数据)
最重要的是,
C/C++编译器开辟的内存缓冲区常常邻近重要的数据结构。现在假设某个函数的堆栈紧接在在内存缓冲区后面时,其中保存的函数返回地址就会与内存缓冲区相邻。此时,恶意攻击者就可以向内存缓冲区复制大量数据,从而使得内存缓冲区溢出并覆盖原先保存于堆栈中的函数返回地址。这样,函数的返回地址就被攻击者换成了他指定的数值;一旦函数调用完毕,就会继续执行“函数返回地址”处的代码。非但如此,
C++的某些其它数据结构,比如v-table、例外事件处理程序、函数指针等,也可能受到类似的攻击。
二、解决内存溢出问题
必须知道内存缓冲区的总长度。
检验内存缓冲区。
提高警惕。
多态性,在c++中指具有不同功能的函数可以用同一个函数名,即可以用同一个函数名调用不同内容的函数。向不同的对象发送用一个消息,不同的对象在接收同样的消息,会产生不同的行为(方法)。
  从系统实现角度来看。多态性分为两类:静态多态性和动态多态性。
  静态多态性:在程序编译时系统就能决定调用哪个函数,因此静态函数有称编译时的多态性(实质上是通过函数的重载实现)
。例如:函数的重载和运算符重载实现.
  动态多态性:运行过程中才动态地确定操作指针所指的对象。主要通过虚函数和重写来实现。

java中的内存溢出和c++中的内存溢出,是一个概念吗~

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
有两种最基本的内存收集方式:一种称为copying或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++编程中如何防止内存溢出问题?
答:(2)以不可靠的方式存取或者复制内存缓冲区。(3)编译器设置的内存缓冲区太靠近关键数据结构。下面来分析这些因素:1.内存溢出问题是C语言或者C++语言所固有的缺陷,它们既不检查数组边界,又不检查类型可靠性 (type-safety)。众所周知,用C/C++语言开发的程序由于目标代码非常接近机器内核,因而能够直接访...

内存溢出的常见原因及如何预防和解决?
答:解决内存溢出的方法包括:首先,调整JVM参数: 增加内存分配,以适应程序需求。其次,检查错误日志: 寻找内存溢出前的其他异常,有助于定位问题。然后,代码审查: 重点检查可能导致内存溢出的代码段,如数据库查询、循环结构等。具体来说,要警惕:避免全量查询: 在数据库查询时,尽量分页获取数据,防止一次性...

如何防止内存溢出
答:避免内存泄漏的几点建议:1、尽早释放无用对象的引用。2、避免在循环中创建对象。3、使用字符串处理时避免使用String,应使用StringBuffer。4、尽量少使用静态变量,因为静态变量存放在永久代,基本不参与垃圾回收。

C语言基本语法知识(十四)数组越界与内存溢出
答:二、防患于未然:避免数组越界实例</ 以下代码展示了如何在循环中避免越界:for(int i = 0; i < 10; ++i) { a[i] = 0; } 记住,越界就像越界篱笆,要时刻保持在安全的范围内。三、内存溢出:溢出的桶与数据容量</ 内存溢出就像桶满水溢出,超出其容量。例如,计时器溢出当超过最...

java 程序的内存溢出问题如何解决?
答:Java程序的内存溢出问题可以通过以下几种方式来解决:1. 增加JVM堆内存大小:可以通过在启动JVM时设置-Xmx和-Xms参数来调整堆内存的大小。例如,"-Xms256m -Xmx1024m"表示最小堆内存为256MB,最大堆内存为1024MB。2. 优化代码:检查代码中是否存在内存泄漏或者不必要的大对象创建。例如,使用完的大...

如何防止java中的内存泄漏
答:1. 检查结果是否在高速缓存中,存在则返回结果; 2. 假如结果不在,那么计算结果; 3. 将结果放入高速缓存,以备将来的操作调用。 这个算法的问题(或者说潜在的内存泄漏)在最后一步。假如操作是分别多次输入,那么存入高速缓存的内容将会非常大。很明显这个方法不可取。 为了避免这种潜在的致命错误设计,程序就必须确定高...

如何避免溢出(计算机)
答:下面讨论内存溢出问题的解决和预防措施。 1、改用受控代码 2002 年 2 月和 3 月,微软公司展开了 Microsoft Windows Security Push 活动。在此期间,我所在的小组一共培训了超过 8500 人,教授他们如何在设计、测试和文档编制过程中解决安全问题。在我们向所有程序设计人员提出的建议中,有一条就是:紧跟微软公司软件...

java分页查数据防止内存溢出问题
答:首先你要明白内存溢出的含义,内存溢出简单的来说就是内存不够了。打个比方:内存就像一个大水缸,数据库就是水库。从数据库中查询数据就像从水库中抽水到大水缸。如果一次性抽取太多的水(超过大水缸的容量),大水缸肯定放不下(溢出了)。分页查询就好比一点一点的抽水到大水缸。jvm有垃圾回收机制,...

java内存泄漏怎么解决
答:第一步,修改JVM启动参数,直接增加内存。(-Xms,-Xmx参数一定不要忘记加。)第二步,检查错误日志,查看“OutOfMemory”错误前是否有其它异常或错误。第三步,对代码进行走查和分析,找出可能发生内存溢出的位置。 已赞过 已踩过< 你对这个回答的评价是? 评论 收起 其他类似问题 2017-08-21 java内存泄漏怎么处理...

android怎么防止内存溢出
答:主要要遵循以下几点:不要为Context长期保存引用(要引用Context就要使得引用对象和它本身的生命周期保持一致)。如果要使用到Context,尽量使用ApplicationContext去代替Context,因为ApplicationContext的生命周期较长,引用情况下不会造成内存泄露问题 在你不控制对象的生命周期的情况下避免在你的Activity中使用...