內存檢驗源碼
① 驅動讀寫內存源碼為什麼總是不成功
這個問題的出現比較普遍,主要有幾個方面:
▉如果使用盜版系統,有可能會出現這樣的問題,建議:使用正版。
★★★★☆如果對電腦沒有影響或偶爾出現不用管它,重啟電腦會自動消失。
【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 方法: