簡單VC記憶體檢測

2021-09-24 06:54:02 字數 4762 閱讀 3283

ios tip

nsarray *array = @[@"1", @"2"];

[array enumerateobjectsusingblock:^(id _nonnull obj, nsuinteger idx, bool * _nonnull stop) ];

nslog(@"hahahha");

/ 依然會輸出每個元素,在列印hahaha

複製**

現在只檢測oc物件

應該查詢

利用clang來進行前端編譯,看是否可以知道一些端倪

1、根據clang --help 命令來檢視clang的用法,但是命令太多我們可以使用

clang --help | grep object 來縮小我們檢視的範圍,這樣就可以一目了然的檢視應該需要哪個命令對原始檔進行轉變

2、-rewrite-objc rewrite objective-c source to c++

根據查詢到線索我們開始對main.m檔案進行編譯

clang -rewrite-objc main.m

很遺憾的是報錯了:

warning: include path for stdlibc++ headers not found; pass '-std=libc++' on the

command line to use the libc++ standard library instead

[-wstdlibcxx-not-found]

main.m:9:9: fatal error: 'uikit/uikit.h' file not found

#import

解決:-x 接下來輸入的檔案是什麼型別的語言

-isysroot 指定系統路徑

如果覺命令長可以使用 別名 (alias),,在~/.bash_profile檔案中宣告:

source ~/.bash_profile

很遺憾的是當我們執行的時候並沒有我們想要的檔案,在從網上查詢

//指定真機的sdk

xcrun -sdk iphoneos clang -rewrite-objc main.m

指定模擬器sdk

xcrun -sdk iphonesimulator clang -rewrite-objc main.m

指定模擬器具體的sdk

xcrun -sdk iphonesimulator10.3 clang -rewrite-objc main.m

複製**

xcrun命令講解

clang命令之後生成的檔案

當乙個timer新增到runloop中的時候,timer就會被runloop強引用, 而timertarget會被timer所強引用,那麼現在問題我們怎麼樣找見這個強引用在什麼地方。我們通過檢視cf原始碼,很大的機率是存放在info中,但是info是乙個void *指標。所以我們應該檢視一下這個info存放了什麼?

cfrunlooptimerref timerref = (__bridge cfrunlooptimerref)timer;

cfrunlooptimercontext cxt;

cfrunlooptimergetcontext(timerref, &cxt);

void * info = cxt.info;

//列印的是每個位元組存放的數字

//我們會發現從第二個位元組開始,後8個位元組是target的位址

for (int i = 1;i < 100; i ++)

}複製**

根據上面**我們把info轉換成乙個struct

typedef struct mc_info mc_info;

複製**

// 這段**沒有crash,並且返回了值。這就表明了block是乙個物件指標。而且系統是吧block包裝成了乙個物件

void(^block)(void) = ^(void);

class cls = [block class];

複製**

void(^block)(void) = ^(void);

class cls = [block class];

while( cls != null && class_getsuperclass(cls) != [nsobject class])

nslog(@"%@", cls);

複製**

如果說你是乙個指標物件,那麼最後的super class一定是[nsobject class],你可以通過runtime的那張表可以看出來。所以繼承與nsoject的那個類一定是block的根類。

檢視circle**,太難了。 學習的點:

.cxx_destruct這是編譯器幫忙加上的**,這個**就是幫助釋放例項變數的。例如我們mrc的環境下

- (void)dealloc 

複製**

.cxx_destruct就相當於執行上面的**。stack overflow, stack overflow**中有點錯誤,就是利用clang生成mrc**引數錯誤,再次糾正一下clang -fno-objc-arc main.m -o test -framework foundation

vim ~/.bash_profile

#貼上下面語句到bash_profile文中

export path='~/bin:$path'

複製**

通過乙個類檔案作為實驗

發現:當類沒有strong修飾的例項變數的時候,這個函式是沒有的。

lldb 的命令,通過watchpoint來查詢例項變數是否會被修改

watchpoint set variable self->_b // self->_b,代表某個例項變數,我們可以不通過kvo進行觀察了

複製**

當block結構中含有含有指標例項變數(__block修飾的),非基本型別(int , bool)。flag 是570425344, 而其他是0,當非0的時,block中desc結構中是含有copydispose函式的。

我們拿到了乙個物件,在oc中物件都是用指標來表示的。明白乙個概念當指標進行加減法操作的時候鎖增加或者減少的位元組數是被加數(被減數)乘以 當前指標所指向的位元組數,在circle這個程式中,首先把乙個存放指標的陣列偽裝成乙個物件,為什麼是存放指標的陣列呢?因為我們的物件都是指標應用的,而且也有記憶體對齊的原則。這個陣列進行釋放,如果其中某個元素被釋放了,那麼這個元素所在的idx,就是這個物件中強引用例項變數的相對物件位址的偏移量。之後我們在把這個物件偽裝成陣列,用idx進行指標偏移。如果對乙個指向物件的指標進行偏移呢?因為開始我們用的是乙個存放指標的陣列,那麼我們在進行偏移的時候,也要把物件指標轉成成乙個存放指標的陣列,也就是void **p,讓後我們用p+ idx可以獲取到強引用的例項變數指標,之後我們進行取值*(p + idx),這樣我們就可以得到例項變數了。

如何向乙個物件的例項變數賦值,通知指標的方式:

@inte***ce person : nsobject

@property (nonatomic, strong) nsstring *name;

@property (nonatomic, assign) int a;

@end

id person_void = (id)person;

char *a = (__bridge void *)person_void + 8;

*a = 10;

// 指明不進行強引用,不進行記憶體管理

__unsafe_unretained id * b = (__unsafe_unretained id *)((__bridge void *)person + 16);

nsobject *name = [nsstring stringwithutf8string:"123"];

*b = name;

nslog(@"person : %@---- ", person.name);

}複製**

1、當我們相對乙個指標進行偏移的,這時候我們應該知曉我們想要偏移多少個位元組,這樣我們就把這個指標轉化什麼型別的指標

2、當用malloc申請一片記憶體,而非使用new alloc 這種方式生成的時候,我們在把這個void *指標轉向 oc物件指標的時候,我們一定加入unsafe_unreatined許可權修飾符

VC檢測記憶體洩露

標頭檔案中加入如下 define crtdbg map alloc include include ifdef debug ifndef dbg new define dbg new new normal block file line define new dbg new endif endif ...

VC 中檢測記憶體洩露

在vc程式設計時,記憶體洩露是個麻煩的事情,特別是有時候會產生比較嚴重的後果,而且這種bug還比較難查.幸好借助一些第三方的軟體,可以方便的找出會產生洩露的地方,比如boundschecker.有時候我們想簡單的了解我們的程式是否存在記憶體洩露,還可以直接使用vc的除錯庫.設定記憶體洩漏檢測 檢測記...

關於記憶體洩漏和記憶體分析檢測的簡單描述

一 記憶體洩漏 首先,解釋一下記憶體洩漏是什麼。大家都知道jvm記憶體結構中,分為了heap區和stack區。而我們寫程式過程中,經常使用到的物件,在jvm記憶體結構中被分為了兩部分來儲存 分別是引用和物件本身的內容。如 integer a new integer 3 在這個物件的使用中,a是引用,...