内存检验源码
① 驱动读写内存源码为什么总是不成功
这个问题的出现比较普遍,主要有几个方面:
▉如果使用盗版系统,有可能会出现这样的问题,建议:使用正版。
★★★★☆如果对电脑没有影响或偶尔出现不用管它,重启电脑会自动消失。
【1】病毒引起的,对电脑全盘杀毒。【升级病毒库,下载最新的专杀工具】
【2】硬件上的原因,主要是内存条不兼容引起的,必要时更换内存。
【3】系统或其它软件引起的。【GHOST版本的系统容易出现这种问题】
【4】打开或关闭IE、QQ、游戏、播放器等出现该内存不能为read或written,首先想到可能就是这款软件的问题,(一般来解决办法就是卸载重新安装、升级或更换其它版本,不行只有卸载该软件,问题才能解决)。
(1)系统本身有问题,及时安装官方发行的补丁,必要时重装系统。
(2)某个软件出现的问题,这里主要是看看开机时运行的软件,(用360等检查开机运行的软件,把不必要运行的软件都去掉),软件冲突,卸载有问题的软件。
★★★☆☆如果上面检查都没问题,下面有两种处理方法可以试试:【如果不行只有恢复或重装系统了】
◆试用命令排除
开始-运行- 输入cmd-- 回车,在命令提示符下输入下面命令
for %1 in (%windir%\system32\*.dll) do regsvr32.exe /s %1回车。
完成后,在输入下面的
for %i in (%windir%\system32\*.ocx) do regsvr32.exe /s %i 回车。
如果怕输入错误,可以复制这两条指令,然后在命令提示符后击鼠标右键,打“粘贴”,回车,耐心等待,直到屏幕滚动停止为止。【重启电脑】
◆◆运行regedit进入注册表, 在HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\ShellExecuteHooks 下,应该只有一个正常的键值{AEB6717E-7E19-11d0-97EE-00C04FD91972}, 将其他的删除。【如果还有一个(默认)不用管它,一般它为空。】
大牛们能不能给小弟写个如题的那个源码?好得话追加悬赏!!!
如果能的话请加上内存_驱动读写1.读小数型 内存_驱动读写1.读整数型源码
纯API 不用到模块哦!
请不要回复直接用模块之类的!~
② Netty源码-内存泄漏检测toLeakAwareBuffer
Netty在实现 ByteBuf 时采用了引用计数法进行 ByteBuf 的回收,使用引用计数法进行回收的 ByteBuf 都扩展了 类,在使用 时需要调用 .retain 方法递增引用计数器,在使用完毕时则需要调用 .release 方法递减引用计数器,当计数器为 0 时,会进行 ByteBuf 的回收工作:池化的 ByteBuf 不会进行实际的内存释放,会将占用的内存归还给内存池,非池化的 ByteBuf 则会直接释放内存(为了叙述简单,后面释放内存则指真正释放内存或者将内存归还给内存池)。
通过上面的描述可知, ByteBuf 的正确回收依赖 retain 和 release 方法的正确调用,内存提前释放(即在使用 ByteBuf 时没有调用 retain 方法,导致提前释放)应用会报错,用户也能及时感知到;但是如果使用完 ByteBuf 忘了调用 release 则会导致内存不能及时得到回收,造成内存泄漏,且内存泄漏用户无法及时感知,久而久之就会发生OOM。为了解决这种问题,Netty采用了内存泄漏检测机制,发生内存泄漏时会通过日志将内存泄漏信息打印出来,报告给用户。
Netty的内存泄漏检测使用了 WeakReference ,即弱引用,了解过Java四种引用类型(强、软、弱、虚)和引用队列( ReferenceQueue )的读者知道,弱引用持有的对象会在虚拟机触发GC时(不管回收之后内存是否够用)被回收掉,如果使用具有引用队列参数的构造函数实例化 WeakReference 时,弱引用持有的对象在GC被回收时,弱引用自身会被放入引用队列。
为了后面能更好的理解Netty内存泄漏检测的细节,下面先看几个弱引用的例子,在下面的几个例子中,我们使用的数据类和自定义的弱引用类子类如下:
好了,三个例子已经介绍完毕,后面在介绍Netty内存泄漏检测时就使用了这里的例子结果,在具体介绍时会和这里的例子一一对应。
Netty中将普通 ByteBuf 转为具有内存泄漏检测功能的 ByteBuf 是通过 AbstractByteBufAllocator.toLeakAwareBuffer 方法实现的,我们直接在Eclipse中看该方法的调用层次即可知道Netty在哪里对 ByteBuf 进行了转换,该方法调用如下图所示:
可见池化内存分配器在分配heap或者direct ByteBuf 时都进行了转换,非池化内存分配器仅在分配direct ByteBuf 时进行了转换。个人理解时采用池化内存需要特别关注内存释放,否则为了实现池化内存预先分配的一大块内存会因为没有释放被很快分配完,造成后面没有内存进行分配。非池化分配的直接内存也需要特别注意释放,放置内存泄漏;非池化分配的heap内存(其实就是一个 byte 数组)则可以在对象被回收时同时被回收掉,发生内存泄漏的可能性较小。
本节介绍Netty中内存泄漏检测相关的类,仅做一个大致介绍,类中的重要方法我们放在后面介绍。
主要负责使用 track 方法对指定的 ByteBuf 进行内存检测泄漏进行追踪,并返回负责追踪的 ResourceLeakTracker 类实例,同时在调用 track 方法时,也会根据指定的检测级别汇报最近的内存泄漏检测结果。该类由工厂类 ResourceLeakDetectorFactory 负责实例化,默认的实现为 ResourceLeakDetector ,在 ResourceLeakDetectorFactory 类的默认实现 中,也会根据用户是否配置了 io.netty.customResourceLeakDetector 来决定采用默认实现 ResourceLeakDetector 还是使用用户自定义的 ResourceLeakDetector ,用户自定义的 ResourceLeakDetector 必须是其子类。
默认实现为 DefaultResourceLeak , DefaultResourceLeak 实现了 ResourceLeakTracker 和 ResourceLeak 接口,同时也继承了类 WeakReference ,是一个弱引用实现。首先,同上面 例2 的结果一样,如果在使用 ByteBuf 时忘了调用 .release 方法,那么将不会调用 DefaultResourceLeak.clear 方法去手动清空该弱引用持有的实际对象,在发生GC时,会由垃圾收集器对弱引用持有的实际对象进行回收,即发生了内存泄漏,同时该弱引用自身也会被加入到引用队列中,该引用队列是 ResourceLeakDetector 的成员域,上面介绍 ResourceLeakDetector 类时说到该类会在用户 track 指定 ByteBuf 是汇报检测结果,该类的汇报数据来源就是引用队列。 DefaultResourceLeak 同时还提供了 record 方法可以让用户在指定时机选择调用,这个方法可以记录用户的调用轨迹(堆栈)。 Record 同时也是一种单链表,在 DefaultResourceLeak 中就使用单链表记录用户的调用轨迹。
DefaultResourceLeak 供用户记录程序调用轨迹的类,也就是 DefaultResourceLeak.record 方法返回的对象,继承自 Throwable ,因此可以使用 Throwable.getStackTrace 方法获得调用轨迹信息,打印在内存泄漏报告中可以让用户更好的排除内存泄漏问题。
在上面介绍 ResourceLeakTracker 时,说到其默认实现为 DefaultResourceLeak , DefaultResourceLeak 提供了 record 方法记录用户的调用轨迹,用户可在调用 ByteBuf 方法时调用 record 方法记录调用轨迹,调用的频率越多,后面在汇报内存泄漏情况时就能打印出越详细的信息,这样也能更方便的排查问题。
Netty提供了两个 ByteBuf 的封装类供选择,就对应不同的 record 调用频率,每个封装类都持有 ResourceLeakTracker 对象,Netty根据配置的内存检测级别(下一节介绍相关配置参数)使用不同的 ByteBuf 封装类。
Netty提供的两个 ByteBuf 封装类就是 和 , 是 的子类, 类仅仅持有 ResourceLeakTracker 对象,但是看其源码,发现没有调用过 record 方法,所以只能知道是否发生了内存泄漏时,无法打印出任何调用轨迹信息。 作为 的子类,在 ByteBuf 的多个方法中调用了 record 方法,所以在发生内存泄漏时,能够打印出比较详细的调用轨迹信息。
在 类中使用了配置参数 io.netty.leakDetection.acquireAndReleaseOnly 来控制是否只是在调用增加或减少引用计数器的方法时才调用 record 方法记录调用轨迹,默认为false。 中 retain 和 release 方法因为改变了引用计数器就直接调用了 record 方法,而该类中的其他方法则根据 io.netty.leakDetection.acquireAndReleaseOnly 的配置决定是否调用 record 方法,这里为了节省篇幅就不列出 类中调用 record 的方法了,读者可自行查看。
在介绍相关配置参数之前,我们先看下Netty提供的内存泄漏检测级别:
Level.ADVANCED 和 Level.PARANOID 使用的 ByteBuf 包装类都是 ,我们上面介绍 ResourceLeakDetector 类时提到该类使用 track 方法对指定的 ByteBuf 进行内存检测泄漏进行追踪,并返回负责追踪的 ResourceLeakTracker 类实例,同时在调用 track 方法时,也会根据指定的检测级别汇报最近的内存泄漏检测结果。如果内存泄漏检测级别为 Level.PARANOID 时则每次调用 track 方法都会进行内存泄漏报告;如果级别为 Level.ADVANCED 或者 Level.SIMPLE 则会以一定频率进行内存泄漏报告,而不是每次 track 都进行报告。
是否关闭Netty内存泄漏检测功能,默认为false。如果该参数配置为false,则默认的内存泄漏检测级别根据此参数的配置为 Level.DISABLED ,否则默认的级别为 Level.SIMPLE 。
配置内存泄漏检测级别的参数,用于老版本的配置参数。
新的内存泄漏检测级别参数,如果没有配置,则会采用老版本参数配置的级别作为最终配置。
在第4节介绍内存泄漏检测相关类时,我们介绍过 DefaultResourceLeak 提供了 record 方法记录用户的调用轨迹,如果当前保存的调用轨迹记录数 Record 大于参数 io.netty.leakDetection.targetRecords 配置的值,那么会以一定的概率(1/2^n)删除头结点之后再加入新的记录,当然也有可能不删除头结点直接新增新的记录。
该参数的默认为4。
上面介绍过,在 类中使用了配置参数 io.netty.leakDetection.acquireAndReleaseOnly 来控制是否只是在调用增加或减少引用计数器的方法时才调用 record 方法记录调用轨迹,默认为false。
在介绍 ResourceLeakDetector 类时提到过,默认的 ResourceLeakDetector 类就是 ResourceLeakDetector ,但是用户可以使用参数 io.netty.customResourceLeakDetector 来决定采用默认实现 ResourceLeakDetector 还是使用用户自定义的 ResourceLeakDetector 。
我们在第二节介绍了Netty中将普通 ByteBuf 转为具有内存泄漏检测功能的 ByteBuf 是通过 AbstractByteBufAllocator.toLeakAwareBuffer 方法实现的。
这里我们先看下该方法的源码:
上面的源码中是调用 AbstractByteBuf.leakDetector.track(buf) 返回 ResourceLeakTracker 类对象的,这里我们看下默认的 ResourceLeakDetector 中 track 方法实现:
我们看到 AbstractByteBufAllocator.toLeakAwareBuffer 对 ResourceLeakDetector.track 返回的 DefaultResourceLeak 和传入的 ByteBuf 对象进行封装,返回了具有内存泄漏检测功能的 ByteBuf 封装类 或其子类 。如果应用程序在使用 ByteBuf 正确调用了 retain 和 release 方法,则在引用计数器为0时,则会清除弱引用持有的实际对象,发生GC时, DefaultResourceLeak 也不会被放入引用队列中(见前面第2节 例3 结果)。
但是如果应用程序在使用 ByteBuf 没有正确调用 retain 和 release 方法,则不会清除弱引用持有的实际对象,此时如果实际上已经没有强引用指向该 ByteBuf ,那么在发生GC时,垃圾收集器会回收该 ByteBuf ,而弱引用 DefaultResourceLeak 会被放入引用队列中(见前面第2节 例2 结果),加入到引用队列中的就是识别到的发生内存泄漏的 ByteBuf 。在 ResourceLeakDetector.track 方法中调用的 reportLeak 输出的就是引用队列中的弱引用 DefaultResourceLeak :
到这里,已经基本上介绍完Netty内存检测的实现原理,下面我们再看下 DefaultResourceLeak.record 是如何记录调用轨迹的:
最后我们再看下 Record 是如何输出调用轨迹的,前面我们说到 Record 继承自类 Throwable ,因此可使用 getStackTrace 方法获取实例化该对象时的调用轨迹,所以上面在输出内存泄漏报告时就调用了 Record.toString 方法: