引用计数gc机制使用不当导致内存泄漏
上一篇文章找同事review了一下,收到的反馈是铺垫太长了,我尽量直入正题,哈哈
最近dbd压测时发现内存泄漏,其实这个问题去年已经暴露了,参见这篇博客【压测周】。当时排查不够仔细,在此检讨下。关于dbd的内存问题,还有这篇博客讨论线程安全,以及这篇博客讨论临时变量的处理。当时还存了一个尾巴,因为用到关联数组进行脏数据管理,这部分数据是怎么释放的一直没搞明白。今天算是搞明白了,这个内存泄漏的bug也源于此。
基于引用计数的gc机制,应该是在引用计数为0的时候释放内存的,lpc也基本没有例外。具体详情可以参看free_svalue的实现,里面基本是引用计数减去1,然后检查是否引用计数为0,若是0就执行相关的Free操作。其中,有一半的篇幅都是讲字符串的释放的,剩下的则是object、buffer、array、mapping、class以及function的释放问题。所以,基本上,lpc不需要像golang一样,停止一切操作做mark and swap的gc操作。也不同于Lua的标记清除,不需要分步执行,只要引用计数为0,立马释放掉。
为什么是基本上呢?因为对于object类型,lpc并没有对其立即释放,而是放到一个链表里面,待主循环里没有函数执行时,再行销毁。这样做,一方面是为了配合复杂的热更新机制,另一方面,则是解决object循环引用的需要。对于对象的销毁,首先调用的是destruct_object, 这个函数最终的作用是为对象打上销毁标志。在这个函数里,针对master object和simul_efun object做了热更新的处理。然后从栈上移除object的所有引用,从object#n列表里移除这个object。最后打上销毁标记,并放入待销毁列表。
下一步,则调用destruct2, 首先将该object的所有变量释放。如果该对象有对自身引用,则因为这一步而引用计数减一,方便接下来释放该对象本身。接着调用free_object, 对象引用次数为0,已打上销毁标记,功成身退,成功析构。
由于在dbd中,没有跑lpc脚本,所有的关联数组(mapping)都是在C层生成和使用的,因此引用计数需要手工维护,这就是万恶之源了。对于脚本层,新建的变量,引用计数都应该为1,退出变量作用域时,则引用计数减一。放入mapping时,引用次数相应加1。而在C层使用mapping时,所有变量的组织都是围绕mapping展开的,变量的生命周期就等同于mapping的生命周期。当序列化数据后,释放数据对应的mapping时,会对其中的所有变量引用计数-1,但依然计数不为0,因此无法释放。
解决的办法也相当简单,变量放入mapping前,先free_svalue,将引用计数变为0,则加入mapping后,引用计数为1,生命周期就同mapping一样了。
引用计数gc机制使用不当导致内存泄漏的更多相关文章
- python中循环引用导致内存泄漏小案例
首先定义一个Person类和一个Dog类,然后分别实例化对象p和d,给p对象添加一个pet属性 给d对象添加一个master属性此时Person和Dog的应用计数都为2,当del p 和del d后P ...
- Android 非静态内部类导致内存泄漏原因深入剖析
背景 上周发现蘑菇街IM-Android代码里面.一些地方代码编写不当.存在内存泄漏的问题.在和疯紫交流的过程中.发现加深了一些理解,所以决定写一下分析思路,相互学习. 内存泄漏 一个不会被使用的对象 ...
- 为什么不取消注册BroadcastReceiver会导致内存泄漏
原始问题是这样 然后扔到了很多Android开发交流群里. 接着产生了很多的见解,我感觉比较靠谱的有以下: 网友对我问题的回答 1.onDestroy被回调代不代表Activity被回收了? 官方是这 ...
- 面试官:小伙子,你给我说一下Java中什么情况会导致内存泄漏呢?
概念 内存泄露:指程序中动态分配内存给一些临时对象,但对象不会被GC回收,它始终占用内存,被分配的对象可达但已无用.即无用对象持续占有内存或无用对象的内存得不到及时释放,从而造成的内存空间浪费. 可达 ...
- objective-c strong导致内存泄漏简单案例
例如: @interface Test:NSObject{ id __strong obj_; } -(void) setObject:(id __strong)obj; @end @implemen ...
- MSDN官方XmlSerializer类导致内存泄漏和性能低
MSDN官方XmlSerializer类使用说明链接: http://msdn.microsoft.com/zh-CN/library/system.xml.serialization.xmlseri ...
- fastjson反序列化使用不当导致内存泄露
分析一个线上内存告警的问题时,发现了造成内存告警的原因是使用fastjson不当导致的. 分析dump发现com.alibaba.fastjson.util.IdentityHashMap$Entry ...
- 重写hashCode方法,导致内存泄漏
package com.nchu.learn.base.reflect; import org.junit.Test; import java.util.Collection; import java ...
- Android一般什么情况下会导致内存泄漏
资料参考:https://blog.csdn.net/u011479990/article/details/78480091 内存泄漏的原因在于生命周期长的对象持有了生命周期短的对象的引用 内存泄漏形 ...
随机推荐
- SQL&&LINQ:左(外)连接,右(外)连接,内连接,完全连接,交叉连接,多对多连接
SQL: 外连接和内连接: 左连接或左外连接:包含左边的表的所有行,如果右边表中的某行没有匹配,该行内容为空(NULL) --outer jion:left join or left outer jo ...
- linux命令:mkdir命令
命令参数: -m, --mode=模式,设定权限<模式> (类似 chmod),而不是 rwxrwxrwx 减 umask -p, --parents 可以是一个路径名称.此时若路径中的 ...
- [Prodinner项目]学习分享_第四部分(完结篇)_Controller层(控制器)
Controller作用: 数据从数据库查询出来后,通过一定的业务逻辑,筛选出来一个结果集,我们最终的目的是要将这个结果集在页面中显示的. Controller就是起到这个作用,将业务逻辑层的结果集调 ...
- Delphi TTable 组件
TTable 是 TDataSet 的派生类,它是基于 BDE 数据库引擎的数据集组件,也是一个较简单的数据组件,可以直接从数据库中获取数据表的数据,只需设置连接的数据库属性(Database) 和所 ...
- 【转】 深入main函数中的参数argc,argv的使用详解
C/C++语言中的main函数,经常带有参数argc,argv,如下: 复制代码 代码如下: int main(int argc, char** argv) 这两个参数的作用是什么呢?argc 是指命 ...
- knn原理与实践
knn法是一种基本分类与回归方法 应用:knn算法不仅可以用于分类,还可以用于回归.. 1.文本分类:文本分类主要应用于信息检索,机器翻译,自动文摘,信息过滤,邮件分类等任务. 2.可以使用knn算法 ...
- 远程实时调试手机上的Web页面
1. 安装 需要Node.js平台, 先安装好后, 打开Node.js command prompt, 通过NPM来安装 weinre npm -g install weinre 2. 启动 ...
- "struct"类型重定义解决办法
#ifndef 在头文件中的作用 在一个大的软件工程里面,可能会有多个文件同时包含一个头文件,当这些文件编译链接成一个可执行文件时,就会出现大量 “重定义”的错误. 在头文件中使用#ifndef #d ...
- 关于makefile
0 Makefile概述 -------------------------------------------------------------------------------- 什么是mak ...
- Linux共享对象之编译参数fPIC
最近在看Linux编程的基础知识,打算对一些比较有趣的知识做一些汇总备忘,本文围绕fPIC展开,学习参考见文末. 在Linux系统中,动态链接文件称为动态共享对象(DSO,Dynamic Shared ...