-
内存泄露
2019-11-01 22:57:28什么是内存泄露: 内存泄漏就是申请了空间却没有成功释放,或者是申请了空间,却丢失了指向该空间的指针,造成内存无法操控, 危害: 内存泄漏会导致系统变慢,卡顿,甚至卡死。 长期运行的程序出现内存泄漏,影响,...什么是内存泄露:
内存泄漏就是申请了空间却没有成功释放,或者是申请了空间,却丢失了指向该空间的指针,造成内存无法操控,
危害:
内存泄漏会导致系统变慢,卡顿,甚至卡死。
长期运行的程序出现内存泄漏,影响,如操作系统,后台服务等,影响很大。内尺寸泄露的分类:(了解)
C/C++ :
程序中一般我们古纳辛两方面:
1 堆内存泄漏
malloc calloc relloc new 等创建出来的空间没有及时调用相应的delete释放掉,
切记: 申请空间和释放空间操作符一定要匹配使用,不匹配可能出错;2 系统资源泄露 :
比方套接字 ,文件描述符。管道等对应的函数没有释放掉。如何检测内存泄漏:
1 Linux下检测:有相应几款工具
2 windows 下 第三方工具 VLD3 其他工具
内存泄露的解决方案:
1 智能指针——————事前预防
2 检测工具——————事后查错如何避免:
1 申请记得释放(不一定有效(异常安全导致走不到释放的指令),所以还得智能指针管理),
2 采用 RALL思想或智能指针来管理资源;
3:有些公司有检漏工具
4 出错再捡漏(工具靠谱性低,代价高) -
内存泄露
2009-10-27 18:26:00内存泄露是指程序中间动态分配了内存,但是在程序结束时没有释放这部分内存,从而造成那一部分内存不可用的情况,重起计算机可以解决,但是也有可能再次发生内存泄露,内存泄露和硬件没有关系,它是由软件设计缺陷...内存泄露是指程序中间动态分配了内存,但是在程序结束时没有释放这部分内存,从而造成那一部分内存不可用的情况,重起计算机可以解决,但是也有可能再次发生内存泄露,内存泄露和硬件没有关系,它是由软件设计缺陷引起的。
应用程序一般使用malloc,realloc,new等函数从堆中分配到一块内存,使用完后,程序必须负责相应的调用free或delete释放该内存
块,否则,这块内存就不能被再次使用,我们就说这块内存泄漏了。所以malloc后一定要free,new了之后一定要delete,creatDC之后一定要deleteDC的。
内存泄漏可以分为4类:1. 常发性内存泄漏。发生内存泄漏的代码会被多次执行到,每次被执行的时候都会导致一块内存泄漏。
2. 偶发性内存泄漏。发生内存泄漏的代码只有在某些特定环境或操作过程下才会发生。常发性和偶发性是相对的。对于特定的环境,偶发性的也许就变成了常发性的。所以测试环境和测试方法对检测内存泄漏至关重要。
3. 一次性内存泄漏。发生内存泄漏的代码只会被执行一次,或者由于算法上的缺陷,导致总会有一块仅且一块内存发生泄漏。比如,在类的构造函数中分配内存,在析构函数中却没有释放该内存,所以内存泄漏只会发生一次。
4. 隐式内存泄漏。程序在运行过程中不停的分配内存,但是直到结束的时候才释放内存。严格的说这里并没有发生内存泄漏,因为最终程序释放了所有申请的内存。但是对于一个服务器程序,需要运行几天,几周甚至几个月,不及时释放内存也可能导致最终耗尽系统的所有内存。所以,我们称这类内存泄漏为隐式内存泄漏。例子:
void f1(void)
{
int * p;
p = new int;
}
执行了F1函数后,p所分配到的内存地址就丢了。找不回那个int内存了,所以这里的内存泄露了!一般多是指内存分配未回收。.用 malloc 分配了,但没有用 free 释放。
2.用 new 分配了,但没有用 delete 删除。
3.用 GlobalAlloc 分配,但没有用 GlobalFree 释放。
4.用 new [] 分配的数组,没有用 delete[] 删除,而是用 delete 删除。
如:
struct A {
int num;
}
struct A* pa;
pa = new A[10];
delete pa; //应该用delete[] pa; -
ThreadLocal原理及内存泄露预防
2018-05-24 13:38:21内存泄露 线程池 参阅:http://www.importnew.com/22039.html 前言 ThreadLocal提供了线程独有的局部变量,可以在整个线程存活的过程中随时取用,极大地方便了一些逻辑的实现。常见的ThreadLocal用法有: ...
参阅:http://www.importnew.com/22039.html前言
ThreadLocal
提供了线程独有的局部变量,可以在整个线程存活的过程中随时取用,极大地方便了一些逻辑的实现。常见的ThreadLocal用法有:- 存储单个线程上下文信息。比如存储id等;
- 使变量线程安全。变量既然成为了每个线程内部的局部变量,自然就不会存在并发问题了;
- 减少参数传递。比如做一个trace工具,能够输出工程从开始到结束的整个一次处理过程中所有的信息,从而方便debug。由于需要在工程各处随时取用,可放入ThreadLocal。
原理
每个Thread内部都有一个Map,我们每当定义一个ThreadLocal变量,就相当于往这个Map里放了一个key,并定义一个对应的value。每当使用ThreadLocal,就相当于get(key),寻找其对应的value。
每个Thread都有一个
{@link Thread#threadLocals}
变量,它就是放k-v的map,类型为{@link java.lang.ThreadLocal.ThreadLocalMap}
。这个map的entry是{@link java.lang.ThreadLocal.ThreadLocalMap.Entry}
,具体的key和value类型分别是{@link ThreadLocal}
(我们定义ThreadLocal变量就是在定义这个key)和{@link Object}
(我们定义ThreadLocal变量的值就是在定义这个value)。(注:实际上key是指向ThreadLocal类型变量的弱引用
WeakReference<ThreadLocal<?>>
,但可以先简单理解为ThreadLocal。)当设置一个ThreadLocal变量时,这个map里就多了一对
ThreadLocal -> Object
的映射。通过一个简单程序来说明上图:
package example.concurrency.tl; /** * @author liuhaibo on 2018/05/23 */ public class ThreadLocalDemo { private static final ThreadLocal<Integer> TL_INT = ThreadLocal.withInitial(() -> 6); private static final ThreadLocal<String> TL_STRING = ThreadLocal.withInitial(() -> "Hello, world"); public static void main(String... args) { // 6 System.out.println(TL_INT.get()); TL_INT.set(TL_INT.get() + 1); // 7 System.out.println(TL_INT.get()); TL_INT.remove(); // 会重新初始化该value,6 System.out.println(TL_INT.get()); } }
分析一下其中一个ThreadLocal变量
TL_INT
在JVM运行时数据区的位置:- Stack-ThreadLocalRef:TL_INT,变量的引用,在栈上;
- Stack-CurrentThreadRef: 当前线程的线程栈,线程私有变量的引用都在线程栈上;
- Heap-ThreadLocal:TL_INT引用所对应的ThreadLocal实例对象;
- Heap-Map:当前线程内部的threadLocals变量所对应的map实例;
- Heap-Entry:上述map的entry;
- Heap-Entry-Key:上述entry的键的弱引用;
- Heap-Entry-Value:上述entry的值的强引用;
对于上述程序,实际上我们在当前线程的threadlocals这个map里放了如下内容:
| TL_INT -> 6 | | TL_STRING -> "Hello, world"|
对于一个普通的map,取其中某个key对应的值分两步:
- 找到这个map;
- 在map中,给出key,得到value。
想取出我们存放在当前线程里的map里的值同样需要这两步。但是,我们不需要告诉jvm map在哪儿,因为jvm知道当前线程,也知道其局部变量map。所以最终的get操作只需要知道key就行了:
int localInt = TL_INT.get();
。
看起来有些奇怪,不同于常规的map的get操作的接口的样子。为什么key使用弱引用
不妨反过来想想,如果使用强引用,当ThreadLocal对象(假设为ThreadLocal@123456)的引用(即:
TL_INT
,是一个强引用,指向ThreadLocal@123456)被回收了,ThreadLocalMap本身依然还持有ThreadLocal@123456的强引用,如果没有手动删除这个key,则ThreadLocal@123456不会被回收,所以只要当前线程不消亡,ThreadLocalMap引用的那些对象就不会被回收,可以认为这导致Entry内存泄漏。那使用弱引用的好处呢?
如果使用弱引用,那指向ThreadLocal@123456对象的引用就两个:
TL_INT
强引用,和ThreadLocalMap中Entry的弱引用。一旦TL_INT
被回收,则指向ThreadLocal@123456的就只有弱引用了,在下次gc的时候,这个ThreadLocal@123456就会被回收。那么问题来了,ThreadLocal@123456对象只是作为ThreadLocalMap的一个key而存在的,现在它被回收了,但是它对应的value并没有被回收,内存泄露依然存在!而且key被删了之后,变成了null,value更是无法被访问到了!针对这一问题,ThreadLocalMap类的设计本身已经有了这一问题的解决方案,那就是在每次
get()
/set()
/remove()
ThreadLocalMap中的值的时候,会自动清理key为null的value。如此一来,value也能被回收了。既然对key使用弱引用,能使key自动回收,那为什么不对value使用弱引用?答案显而易见,假设往ThreadLocalMap里存了一个value,gc过后value便消失了,那就无法使用ThreadLocalMap来达到存储全线程变量的效果了。(但是再次访问该key的时候,依然能取到value,此时取得的value是该value的初始值。即在删除之后,如果再次访问,取到null,会重新调用初始化方法。)
内存泄露
总结一下内存泄露(本该回收的无用对象没有得到回收)的原因:
- 弱引用一定程度上回收了无用对象,但前提是开发者手动清理掉ThreadLocal对象的强引用(如
TL_INT
)。只要线程一直不死,ThreadLocalMap的key-value一直在涨。
解决方法:当某个ThreadLocal变量(比如:
TL_INT
)不再使用时,记得TL_INT.remove()
,删除该key。比如在spring mvc的场景下,每次使用线程处理完一个请求,就在afterCompletion里清掉线程里的ThreadLocal变量:
/** * @author caikang * @date 2017/04/07 */ public class UserHolder { private static final ThreadLocal<User> userThreadLocal = new ThreadLocal<User>(); public static void set(User user){ userThreadLocal.set(user); } public static User get(){ return userThreadLocal.get(); } public static void remove(){ userThreadLocal.remove(); } } /** * @author caikang * @date 2017/04/07 */ public class UserInterceptor extends HandlerInterceptorAdapter { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { UserHolder.set(new User()); return true; } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { UserHolder.remove(); } }
通常,我们需要 保证作为key的TL_INT类型能够被全局访问到,同时也必须 保证其为单例,因此,在一个类中将其设为static类型便成为了惯用做法。
线程池
使用了线程池,可以达到“线程复用”的效果。但是归还线程之前记得清除ThreadLocalMap,要不然再取出该线程的时候,ThreadLocal变量还会存在。这就不仅仅是内存泄露的问题了,整个业务逻辑都可能会出错。
解决方法参考:
/** * Method invoked upon completion of execution of the given Runnable. * This method is invoked by the thread that executed the task. If * non-null, the Throwable is the uncaught {@code RuntimeException} * or {@code Error} that caused execution to terminate abruptly. * * <p>This implementation does nothing, but may be customized in * subclasses. Note: To properly nest multiple overridings, subclasses * should generally invoke {@code super.afterExecute} at the * beginning of this method. * ... some deleted ... * * @param r the runnable that has completed * @param t the exception that caused termination, or null if * execution completed normally */ protected void afterExecute(Runnable r, Throwable t) { }
override
{@link ThreadPoolExecutor#afterExecute(r, t)}
方法,对ThreadLocalMap进行清理,比如:protected void afterExecute(Runnable r, Throwable t) { // you need to set this field via reflection. Thread.currentThread().threadLocals = null; }
参考:https://stackoverflow.com/a/30328722/7676237
附:强引用-软引用-弱引用
- 强引用:普通的引用,强引用指向的对象不会被回收;
- 软引用:仅有软引用指向的对象,只有发生gc且内存不足,才会被回收;
- 弱引用:仅有弱引用指向的对象,只要发生gc就会被回收。
看一个例子就明白强引用、软引用、弱引用的区别:
package example.reference; import java.lang.ref.SoftReference; import java.lang.ref.WeakReference; /** * @author liuhaibo on 2018/03/06 */ public class WeakRefDemo { public static void main(String... args) { // all these objects have a strong reference Object a = new Object(); Object b = new Object(); Object c = new Object(); // other references to these objects Object strongA = a; SoftReference<Object> softB = new SoftReference<>(b); WeakReference<Object> weakC = new WeakReference<>(c); // free the former strong references to these objects: // there is still a strong reference(strongA) to the first object a = null; // only a soft reference(softB) refers to the second object b = null; // only a weak reference(weakC) refers to the third object c = null; System.out.println("Before gc..."); System.out.println(String.format("strongA = %s, softB = %s, weakC = %s", strongA, softB.get(), weakC.get())); System.out.println("Run GC..."); System.gc(); // object with only soft reference will be cleaned only if memory is not enough: 用来做缓存很不错 // object with only weak reference will be cleaned after a gc operation: System.out.println("After gc..."); System.out.println(String.format("strongA = %s, softB = %s, weakC = %s", strongA, softB.get(), weakC.get())); } }
Output:
Before gc... strongA = java.lang.Object@3af49f1c, softB = java.lang.Object@19469ea2, weakC = java.lang.Object@13221655 Run GC... After gc... strongA = java.lang.Object@3af49f1c, softB = java.lang.Object@19469ea2, weakC = null
-
什么是内存泄露,如何避免内存泄露 C++
2018-06-29 21:01:08定义 内存泄露(memory lock)是指由于疏忽或错误... 一般常说的内存泄露是指堆内存的泄露,堆是动态分配内存的,并且可以分配使用很大的内存,使用不好会产生内存泄露,使用不好会产生内存泄露。频繁的使用mallo...定义
- 内存泄露(memory lock)是指由于疏忽或错误造成程序未能释放已经不再使用的内存的情况。
进一步解释
- 内存泄露其实并非指内存再物理上的小时,而是在应用程序分配某段内存后,由于涉及错误,死去了对该内存的控制,因而造成了内存的浪费。
- 一般常说的内存泄露是指堆内存的泄露,堆是动态分配内存的,并且可以分配使用很大的内存,使用不好会产生内存泄露,使用不好会产生内存泄露。频繁的使用malloc和free会产生内存碎片(类似磁盘碎片)。
- 一般使用malloc、calloc、realloc、new等函数从堆中分配到一块内存,使用完后,也应该对应的调用free或delete来释放内存块,否则这块内存就不能再次使用,造成内存泄露
- 对new或malloc出的指针进行重新赋值,也会导致内存泄露
避免内存泄露
- 方法1:内部封装
参考:https://blog.csdn.net/yes_I_am/article/details/51182971
程序内存分配中栈区和堆区的特点不同,栈区的数据生命周期结束时系统会自动回收栈上的内存,而堆上的内存由程序员自己分配,堆上数据的生命周期结束时系统不会自动回收它的内存,而是需要程序员手动释放,这样就很容易造成内存泄露。
想要避免内存泄露就需要用到栈和堆的特性,以及C++析构函数的特性,在C++中,当class对象的生命周期结束时,class对象会自动调用自己的自购函数来释放类实例化时构造函数所申请的内存空间。
具体方法
将动态内存的申请放在类的构造函数中,然后在类的析构函数中手动释放构造函数申请的内存空间,最后将class对象定义在程序栈上。这样在class对象生命周期结束时,系统会自动回收栈上class对象所占的内存,同时class对象在他的生命周期结束时将会自动调用自己的析构函数来释放构造函数申请的堆内存空间,这样就可以间接地使用程序栈来管理分配的内存,也间接地避免了程序运行过程中内存的泄露。
代码实现
参考:http://www.cppblog.com/kangnixi/archive/2010/02/15/107878.aspx
- 方法2:智能指针
参考:https://blog.csdn.net/xt_xiaotian/article/details/5714477
参考:http://www.cnblogs.com/xiehongfeng100/p/4645555.html#autoid-1-0-0
参考:https://www.cnblogs.com/lanxuezaipiao/p/4132096.html
对于编译器来说,智能指针实际上是一个栈对象,并非指针类型,在栈对象生命期即将结束时,智能指针通过析构函数释放有它管理的堆内存。自C++11起,C++标准提供两大类型的智能指针:
- Class shared_ptr实现共享式拥有(shared ownership)概念。多个智能指针可以指向相同对象,该对象和其相关资源会在“最后一个引用(reference)被销毁”时释放。为了在结构复杂的情境中执行上述工作,标准库提供了weak_ptr、bad_weak_ptr和enable_shared_from_this等辅助类。
- Class unique_ptr实现独占式拥有(exclusive ownership)或严格拥有(strict ownership)概念,保证同一时间内只有一个智能指针可以指向该对象。一旦拥有者被销毁或变成空,或开始拥有另一个对象,先前拥有的那个对象就会被销毁,其任何相应资源也会被释放。它对于避免资源泄露(resource leak)--例如“以new创建对象后因为发生异常而忘记调用delete”--特别有用。
注:C++98中的Class auto_ptr在C++11中已不再建议使用。
使用智能指针的原因
- 智能指针能够帮我们处理资源泄露问题;
- 它也能够帮我们处理空悬指针的问题;
- 它还能够帮我们处理比较隐晦的由异常造成的资源泄露。
C++内存管理
-
android:内存泄露与内存溢出区别、内存泄露定位
2017-06-08 15:49:40今天道长主要说说内存泄露的定位,了解一下内存泄露和内存溢出的定义及区别。下面咱们开始……一、内存泄露与内存溢出的区别说到内存泄露,咱们首先要了解一下内存泄漏的定义。由于有些小伙伴对于内存溢出和内存泄露... -
C/C++什么是内存泄露,内存泄露如何避免?
2020-07-01 20:46:51C/C++什么是内存泄露,内存泄露如何避免?1. 内存溢出2. 内存泄漏3. 造成内存泄露常见的三种情况3.1 指针重新赋值3.2 错误的内存释放3.3 返回值的不正确处理4. 如何避免内存泄露?5. 内存泄露检测工具valgrind 1. ... -
内存泄露和内存溢出
2019-04-18 23:27:22内存泄露 内存泄露(memory leak),是指程序在申请内存后,无法释放已申请的内存空间,一次内存泄露危害可以忽略,但内存泄露堆积后果很严重,无论多少内存,迟早会被占光。 内存溢出 内存溢出(out of memory)... -
android内存泄露:4、Toast的错误使用导致内存泄露
2020-04-16 23:47:19目录 一、前言 二、Toast的错误使用导致内存泄露 1、新建一个 Module,写主界面 MainActivity,布局 ...详细可参考博文:原创android内存泄露:3、Handler的错误使用导致内存泄露,这篇文章我们将介绍:Toast... -
troubleshoot之:使用JFR解决内存泄露
2020-08-12 09:30:06文章目录简介一个内存泄露的例子使用JFR和JMC来分析内存泄露OldObjectSample总结 简介 虽然java有自动化的GC,但是还会有内存泄露的情况。当然java中的内存泄露跟C++中的泄露不同。 在C++中所有被分配的内存对象都... -
使用Xcode和Instruments调试解决iOS内存泄露
2012-11-28 15:05:15虽然iOS 5.0版本之后加入了ARC机制,由于相互引用关系比较复杂时,内存泄露还是可能存在。所以了解原理很重要。 这里讲述在没有ARC的情况下,如何使用Instruments来查找程序中的内存泄露,以及NSZombieEnabled设置... -
内存泄露,内存溢出
2017-12-06 21:07:02一:内存泄漏,内存溢出内存泄露:是指无用对象(不再使用的对象)持续占有内存或无用对象的内存得不到及时释放,从而造成的内存空间的浪费称为内存泄露。内存泄露有时不严重且不易察觉,这样开发者就不知道存在内存... -
Android内存泄露
2017-01-18 10:08:16本篇博客主要是记录一下Android内存泄露相关的问题。 网上有很多介绍内存泄露的文章,自己摘取了一些比较有价值的内容, 同时增加了一些自己的理解。 -
内存泄露与内存溢出
2016-08-30 22:03:011、内存泄露(Memory Leak)内存泄露是指我们在使用动态存储时分配的空间,在使用后没有释放,这样导致内存单元没有被回收利用,这就是内存泄露。 在java中因为动态创建的对象是保存在堆中的,因此指的是堆内存... -
【Android】java Handler导致内存泄露分析
2019-12-17 21:51:42Handler导致内存泄露分析 有关内存泄露请猛戳内存泄露 Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { // do something. } } 当我们这样创建Handler的时候Android ... -
JAVA 内存泄露详解(原因、例子及解决)
2016-05-05 20:24:58Java的一个重要特性就是通过垃圾收集器(GC)自动管理内存的回收,而不...理论上Java中所有不会再被利用的对象所占用的内存,都可以被GC回收,但是Java也存在内存泄露,但它的表现与C++不同。 JAVA 中的内存管... -
内存泄露Demo leaky app
2012-11-28 11:25:32内存泄露Demo leaky app -
Android内存泄露与内存溢出
2016-12-26 20:50:17内存泄露的危害: (1)过多的内存泄露最终会导致内存溢出(OOM)(2)内存泄露导致可用内存不足,会触发频繁GC,不管是Android2.2以前的单线程GC还是现在的CMS和G1,都有一部分的操作会导致用户线程停止(就是所谓... -
C++内存泄露
2016-09-02 09:20:48C++中的内存泄露一般指堆中的内存泄露。堆内存是我们手动malloc/realloc/new申请的,程序不会自动回收,需要调用free或delete手动释放,否则就会造成内存泄露。内存泄露其实还应该包括系统资料的泄露,比如socket... -
Java内存管理之内存泄露是什么?什么情况下会导致内存泄露?
2018-12-08 19:49:40虽然Java拥有垃圾回收机制,但同样会出现内存泄露问题,我们说一下比较主要的三种情况。 1. 静态类的使用 诸如 HashMap、Vector 等集合类的静态使用最容易出现内存泄露,因为这些静态变量的生命周期和应用程序一致... -
【Android程序优化,避免内存泄露】- [实战一]:避免内存泄露的最后一道墙,使用leakcanary分析程序中的...
2016-03-30 00:14:36打算写一个系列吧,包括程序怎么优化,如何避免内存泄露,出现内存泄露该如何处理分析。 这个系列应该会很长,首先会根据实际项目中遇到的东西总结整理上来,然后会收集网上相关好资源分享。 内容大致分两种,一种是... -
c++内存泄露(三):定位和解决内存泄露
2017-10-11 17:42:33如果编写的c++程序出现内存泄露了,不要慌忙,你要相信任何错误都是人为造成的,只要是人为的,你一定能找到错误所在,只不过是时间的问题而已。在面对内存泄露,如果程序不是特别长的话,你可以使用人工校验,着重... -
实战Go内存泄露
2019-05-18 17:42:28最近解决了我们项目中的一个内存泄露问题,事实再次证明pprof是一个好工具,但掌握好工具的正确用法,才能发挥好工具的威力,不然就算你手里有屠龙刀,也成不了天下第一,本文就是带你用pprof定位内存泄露问题。...
-
数学建模-零件参数设计的数学模型
-
springboot的@Value 的map注入
-
迷宫-源码
-
项目管理工具与方法
-
瓦级连续双波长输出Nd:YAP/KTP稳频激光器
-
Mysql数据库面试直通车
-
cocos creator运行正常,微信开发者工具中报错XXX is not defined.
-
upload-labs第四关 pass-04 htaccess绕过
-
GC_Lab8_GetToKnow:Grand Circus C#.NET 2021 Q1 DT Lab 8了解您的同学-源码
-
Python启蒙到架构师的核心技术精讲课程
-
【Java面试题第五期】Java中垃圾收集算法有哪些?
-
龙芯实训平台应用实战(希云)
-
Typora+PicGo-(SM.MS/七牛/Gitee)实现自动上传图片
-
Windows系统管理
-
1178. Number of Valid Words for Each Puzzle(Leetcode每日一题-2021.02.26)--抄答案
-
upload-labs第五关 pass-05 大小写绕过
-
单调队列——定长区间最值问题
-
基于python的dango框架购物商城毕业设计毕设源代码使用教程
-
工程制图 AutoCAD 2012 从二维到三维
-
leetcode:我存储所有leetcode问题的存储库-源码