-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathatom.xml
More file actions
437 lines (349 loc) · 48.2 KB
/
Copy pathatom.xml
File metadata and controls
437 lines (349 loc) · 48.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>Sire的技术生活</title>
<subtitle>打造自己心中的世界</subtitle>
<link href="/atom.xml" rel="self"/>
<link href="http://yoursite.com/"/>
<updated>2017-07-03T00:32:34.000Z</updated>
<id>http://yoursite.com/</id>
<author>
<name>Sire</name>
</author>
<generator uri="http://hexo.io/">Hexo</generator>
<entry>
<title>机器学习——微积分求极值</title>
<link href="http://yoursite.com/2017/07/03/machine-learning-6/"/>
<id>http://yoursite.com/2017/07/03/machine-learning-6/</id>
<published>2017-07-03T01:02:37.000Z</published>
<updated>2017-07-03T00:32:34.000Z</updated>
<content type="html"><p><img src="/images/屏幕快照 2017-06-27 下午5.35.50.png" alt=""></p>
<p>求代价函数最小值问题,如果是正规方程,我们可以对每个参数值求导并令导数为0。<br>我们队最小二乘法进行参数求导,最终得到的关系如上图所示</p>
<p><img src="/images/屏幕快照 2017-06-28 下午11.40.00.png" alt=""></p>
<p>如果使用了正规方程,那么就不需要进行特征缩放(特征变量归一化处理,便于进行梯度下降)取相似范围,因为最终算出来的结果是一样的.</p>
<p>我们可以使用matlab或者Octave来进行正规方程的计算。<br>推荐使用pin函数来进行计算,因为正规方程中设计的矩阵逆运算,即是矩阵没有逆矩阵也会给出结果。<br>那么是什么导致举证不可逆呢?</p>
<p>存在多余的相似特征,我们可以删除他</p>
<p>太多的特征导致行数小于列数,我们可以通过删减特征以使举证为方阵,矩阵的可逆是建立在方阵基础上的</p>
</content>
<summary type="html">
<p><img src="/images/屏幕快照 2017-06-27 下午5.35.50.png" alt=""></p>
<p>求代价函数最小值问题,如果是正规方程,我们可以对每个参数值求导并令导数为0。<br>我们队最小二乘法进行参数求导,最终得到的关系如上图所示</p>
</summary>
<category term="机器学习" scheme="http://yoursite.com/categories/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/"/>
<category term="技术教程" scheme="http://yoursite.com/tags/%E6%8A%80%E6%9C%AF%E6%95%99%E7%A8%8B/"/>
</entry>
<entry>
<title>机器学习——特征缩放</title>
<link href="http://yoursite.com/2017/07/03/machine-learning-5/"/>
<id>http://yoursite.com/2017/07/03/machine-learning-5/</id>
<published>2017-07-03T01:02:37.000Z</published>
<updated>2017-07-03T00:29:03.000Z</updated>
<content type="html"><p><img src="/images/屏幕快照 2017-06-27 下午5.35.50.png" alt=""></p>
<p>特征缩放一般希望将特征值缩放到-1 到 1之间或者非常相近的区域之间,这样做的原因是为了便于梯度下降算法运行的更快。<br>只要缩放到相近似的范围即可</p>
<p>如图缩放的方式为:<br>(x-u)/s ,其中x是特征值,u是均值,s是值范围。</p>
<p>如何确定梯度下降运行正确?</p>
<p>如何确定学习速率?</p>
<p><img src="/images/屏幕快照 2017-06-28 下午12.16.05.png" alt=""></p>
<p>由梯度下降公式可知,学习速率越大,j函数值下降的越快,越快速趋缓,在较少的迭代中,函数值迅速趋向缓和表明学习速率大</p>
<p>如果学习速率太小,收敛速度慢,如果学习速率太大,可能会错过收敛点</p>
<p>为了确定学习速率多少合适,可以先设定一个学习速率,迭代几次值,画出二维坐标,连线看先下降的趋势,如上图,通过下降趋势来判断设置的学习速率是偏大还是偏小</p>
<p>面对一个事物,我们选取什么特征进行建模需要多方考虑,有时候需要将多个特征综合起来表示成一个特征,比如房子的宽高我们可以表示为面积</p>
</content>
<summary type="html">
<p><img src="/images/屏幕快照 2017-06-27 下午5.35.50.png" alt=""></p>
<p>特征缩放一般希望将特征值缩放到-1 到 1之间或者非常相近的区域之间,这样做的原因是为了便于梯度下降算法运行的更快。<br>只要缩放到相近似的
</summary>
<category term="机器学习" scheme="http://yoursite.com/categories/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/"/>
<category term="技术教程" scheme="http://yoursite.com/tags/%E6%8A%80%E6%9C%AF%E6%95%99%E7%A8%8B/"/>
</entry>
<entry>
<title>机器学习——分类及其代价函数</title>
<link href="http://yoursite.com/2017/07/03/machine-learning-7/"/>
<id>http://yoursite.com/2017/07/03/machine-learning-7/</id>
<published>2017-07-03T01:02:37.000Z</published>
<updated>2017-07-03T00:40:17.000Z</updated>
<content type="html"><p><img src="/images/屏幕快照 2017-06-30 下午4.34.12.png" alt=""></p>
<p>一个这样的例子:0表示没有得肿瘤 1表示得了恶性肿瘤,在二维坐标系上建立关系,横轴表示肿瘤大小,纵轴代表是否得了恶性肿瘤。</p>
<p><img src="/images/屏幕快照 2017-06-30 下午4.39.02.png" alt=""></p>
<p>我们画一条线去拟合这些点,设置一个阈值,比如0.5,函数输出值大于0.5归类1 ,函数小于0.5归类0。</p>
<p><img src="/images/屏幕快照 2017-06-30 下午4.46.28.png" alt=""></p>
<p>当我们仅仅用线性回归去拟合,线性回归的的取值域往往不在[0,1]之间,这显然是不合理的。</p>
<p>下面引出logistic线性回归,解决二分类问题。</p>
<p>上面说到,我们希望函数的输出在0与1之间,logistic线性函数即满足这种特征,logistic函数解决了输出值必须在0,1内的问题,但是划分边界需要假设函数(决策边界)自己去定义。<br>hθ(x)=g(θTx)<br>z=θTx<br>g(z)=11+e−z</p>
<p><img src="/images/屏幕快照 2017-06-30 下午5.00.33.png" alt=""></p>
<p>我们预测一个病人得了恶性肿瘤的概率<br>P(y=1|x;theTa) 读作在给定x,参数为theTa的情况下,得了恶性肿瘤的概率。</p>
<p>决策边界</p>
<p><img src="/images/屏幕快照 2017-06-30 下午5.12.57.png" alt=""></p>
<p>假设函数为</p>
<p><img src="/images/屏幕快照 2017-06-30 下午5.26.28.png" alt=""></p>
<p>有图可知,要是y = 1 ,那么g(z)必须大于或等于0.5 ,此时,z&gt;0,即h(x)&gt;=0<br>假设参数已经知道,分别 -3 ,1,1,那么假设函数为<br>h(x) = -3 + x1 + x2;<br>-3+x1+x2 &gt;=0</p>
<p><img src="/images/屏幕快照 2017-06-30 下午5.30.40.png" alt=""></p>
<p>那么这条线成为决策边界,那么h(x)=0实际上就是决策边界。但是并非所有情况下,决策边界都是线性的。</p>
<p><img src="/images/屏幕快照 2017-06-30 下午5.42.16.png" alt=""></p>
<p>如图所示,决策边界应当是个圆形,那么我我们可以使用多项式的方式去拟合这个边界。</p>
<p>逻辑回归的代价函数</p>
<p>我们不能直接使用最小二乘法作为逻辑回归的代价函数,因为将函数带入后会发现,代价函数是非凸函数,这给求极值带来了困难。因为h(x)的值域为[0,1]<br>我们使用去log的方式代替<br>J(θ)=1m∑i=1mCost(hθ(x(i)),y(i))<br>Cost(hθ(x),y)=−log(hθ(x)) if y = 1<br>Cost(hθ(x),y)=−log(1−hθ(x)) if y = 0</p>
<p><img src="/images/屏幕快照 2017-07-02 下午6.00.46.png" alt=""></p>
<p>通过变换代价函数为等方向的凸,使得求极值跟容易。</p>
</content>
<summary type="html">
<p><img src="/images/屏幕快照 2017-06-30 下午4.34.12.png" alt=""></p>
<p>一个这样的例子:0表示没有得肿瘤 1表示得了恶性肿瘤,在二维坐标系上建立关系,横轴表示肿瘤大小,纵轴代表是否得了恶性肿瘤。</p>
<p><img
</summary>
<category term="机器学习" scheme="http://yoursite.com/categories/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/"/>
<category term="技术教程" scheme="http://yoursite.com/tags/%E6%8A%80%E6%9C%AF%E6%95%99%E7%A8%8B/"/>
</entry>
<entry>
<title>机器学习——代价函数</title>
<link href="http://yoursite.com/2017/06/26/machine-learning-3/"/>
<id>http://yoursite.com/2017/06/26/machine-learning-3/</id>
<published>2017-06-26T01:02:37.000Z</published>
<updated>2017-06-26T02:25:35.000Z</updated>
<content type="html"><p><img src="/images/屏幕快照 2017-06-25 下午7.03.02.png" alt=""></p>
<p>如上所示,给定一个训练集,假设数据拟合的模型结构为一元线性结构,我们需要解决的问题是如何根据数据集,求解出合适的参数值。不同的参数值决定了拟合直线的走向。</p>
<p>当我们求解出了参数值,对模型进行了拟合后,需要评价模型预测的精度如何,需要一个对模型的评价标准,代价函数便是做这样的工作。</p>
<p>在线性回归问题中,常用的代价函数是方差平方和(也叫最小二乘法)。使用预测值与真实值差值的平房和来对模型的精度进行评价。</p>
<p><img src="/images/屏幕快照 2017-06-25 下午7.17.28.png" alt=""></p>
<p>最合理的参数值应当使代价函数的值最小,由此参数的求解问题,转化到数学求极值问题。</p>
<p><img src="/images/屏幕快照 2017-06-25 下午7.18.44.png" alt=""></p>
<p>而代价函数的极值问题,不同的函数其极值的分布可能是复杂的,比较简单的二次函数的代价函数模型可能如下:</p>
<p><img src="/images/屏幕快照 2017-06-25 下午7.41.28.png" alt=""></p>
<p>显然当参数值取1的时候函数取最小值,由此确定参数值</p>
<p>假设现在需要求的参数值有两个,那么最后的图可能是这样的:</p>
<p><img src="/images/屏幕快照 2017-06-25 下午7.49.54.png" alt=""></p>
<p>我们去掉J轴,用地理学中等高线的概念的表示上面的三维图,等高线的高度从外圈向内圈递减,同一条线的上J轴值相等如下右图所示:</p>
<p><img src="/images/屏幕快照 2017-06-25 下午8.00.00.png" alt=""></p>
<p>在这两个参数所建立的二维坐标系中,每确定一组参数值,将有对应的J轴值,由图可知,J轴的最小值是最小圆的中心点。。</p>
<p>对于更多为的参数,我们无法画出这样的图形进行人工筛选求解,会通过梯段算法或者牛顿方法进行求解</p>
</content>
<summary type="html">
<p><img src="/images/屏幕快照 2017-06-25 下午7.03.02.png" alt=""></p>
<p>如上所示,给定一个训练集,假设数据拟合的模型结构为一元线性结构,我们需要解决的问题是如何根据数据集,求解出合适的参数值。不同的参数值决定了拟合直线
</summary>
<category term="机器学习" scheme="http://yoursite.com/categories/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/"/>
<category term="技术教程" scheme="http://yoursite.com/tags/%E6%8A%80%E6%9C%AF%E6%95%99%E7%A8%8B/"/>
</entry>
<entry>
<title>机器学习——线性回归</title>
<link href="http://yoursite.com/2017/06/26/machine-learning-2/"/>
<id>http://yoursite.com/2017/06/26/machine-learning-2/</id>
<published>2017-06-26T01:02:37.000Z</published>
<updated>2017-06-26T02:00:32.000Z</updated>
<content type="html"><p>假设我们有一个房价问题</p>
<p><img src="/images/屏幕快照 2017-06-25 下午6.48.21.png" alt=""></p>
<p>给定的样本数据如图所示,现在需要根据这些点拟合出一个线性函数,以便于进行房价预测。</p>
<p>将样本数据进行整理如下:<br><img src="/images/屏幕快照 2017-06-25 下午6.50.28.png" alt=""></p>
<p>m表示样本个数,x表示输入值,y表示输入出值。</p>
<p>使用<img src="/images/屏幕快照 2017-06-25 下午6.53.56.png" alt="">表示样本第i行样本数据。</p>
<p>我们通过如如样本数据给学习算法,确定学习算法的参数值后得到学习算法,然后使用学习算法进行输出值的预测。</p>
<p><img src="/images/屏幕快照 2017-06-25 下午6.56.41.png" alt=""></p>
</content>
<summary type="html">
<p>假设我们有一个房价问题</p>
<p><img src="/images/屏幕快照 2017-06-25 下午6.48.21.png" alt=""></p>
<p>给定的样本数据如图所示,现在需要根据这些点拟合出一个线性函数,以便于进行房价预测。</p>
<p>将样本数据
</summary>
<category term="机器学习" scheme="http://yoursite.com/categories/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/"/>
<category term="技术教程" scheme="http://yoursite.com/tags/%E6%8A%80%E6%9C%AF%E6%95%99%E7%A8%8B/"/>
</entry>
<entry>
<title>机器学习——梯度下降</title>
<link href="http://yoursite.com/2017/06/26/machine-learning-4/"/>
<id>http://yoursite.com/2017/06/26/machine-learning-4/</id>
<published>2017-06-26T01:02:37.000Z</published>
<updated>2017-06-26T02:45:01.000Z</updated>
<content type="html"><p> 本讲讲解梯度下降。<br>问题:对于关于参数的函数J,求解参数值是的J的取值最小</p>
<p><img src="/images/屏幕快照 2017-06-25 下午10.23.53.png" alt=""></p>
<p>主要思想:先任意设置参数初始值,通过不断迭代逐步使得J的取值达到最小,直到小于我们设定的阈值。</p>
<p><img src="/images/屏幕快照 2017-06-25 下午10.30.35.png" alt=""></p>
<p>形象的说法:我们将函数平面看成是地形图,我们任意的站在山坡,希冀能以最快到速度跑到山底,那么选择什么方向最快呢,当然是<br>最陡峭的方向最快,这样在固定步长下,每步都选择最陡峭的方向往下走,当然可以最快跑到山底。这就是梯度下降原理的形象比喻,其中“最陡峭的方向”<br>在函数中即是函数在该点的梯度方向,通过梯度下降,总能找到局部最低点,并且不同的初始值可能会影响最终的最低点。</p>
<p>具体公式表达如下:</p>
<p><img src="/images/屏幕快照 2017-06-25 下午10.57.16.png" alt=""></p>
<p>上图的参数更新方式注意两点:一是参数值是多个的情况下,每步迭代需要对每个参数进行梯度求导和计算<br>二是正确的参数迭代过程应当如上左图所示,右图的参数更新方式会将前一个已经更新的参数代入未更新的参数中进行更新,这会产生微小的错误。<br>方向导数前的系数疏于上叫做学习速率,学习速率太小会导致迭代次数多,学习速率太大,有可能会错过最优点。</p>
<p>随着梯度下降算法的迭代,约接近最小值,每次迭代的该变量会越来越小,这是因为接近最小值是梯度方向越来越缓,当找到最小点是,该点的偏导数为0.</p>
<p>迭代逼近:</p>
<p><img src="/images/屏幕快照 2017-06-25 下午11.48.06.png" alt=""></p>
<p>以上的梯度下降称为批梯度下降,“批”的概念体现在每次迭代都需要遍历全部的样本,对应的还有随机梯度下降,每次只用一个样本,但是精度上比前者低。</p>
<p>梯度下降求得最优解一般是局部最优解,当代价函数是凸函数时,求得的是全局最优解。</p>
</content>
<summary type="html">
<p> 本讲讲解梯度下降。<br>问题:对于关于参数的函数J,求解参数值是的J的取值最小</p>
<p><img src="/images/屏幕快照 2017-06-25 下午10.23.53.png" alt=""></p>
<p>主要思想:先任意设置参数初始值,通过不断迭代逐
</summary>
<category term="机器学习" scheme="http://yoursite.com/categories/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/"/>
<category term="技术教程" scheme="http://yoursite.com/tags/%E6%8A%80%E6%9C%AF%E6%95%99%E7%A8%8B/"/>
</entry>
<entry>
<title>机器学习——学习类型</title>
<link href="http://yoursite.com/2017/06/26/machine-learning-1/"/>
<id>http://yoursite.com/2017/06/26/machine-learning-1/</id>
<published>2017-06-26T00:41:19.000Z</published>
<updated>2017-06-26T01:52:49.000Z</updated>
<content type="html"><p>监督学习:算法的训练有训练集数据和测试集数据,并且数据集都要正确的实际答案,基于这些数据进行算法的建模,并用此模型对给定的输入值,预测输出。应用领域如股市预测,房价预测等。</p>
<p>无监督学习:给定一个数据即,没有人告诉你改如何处理,也不知道数据的类别,你需要依据这些数据进行建模,找出这些数据集中数据的关系,比如聚类。应用领域有客户分组,认知识别等。</p>
</content>
<summary type="html">
<p>监督学习:算法的训练有训练集数据和测试集数据,并且数据集都要正确的实际答案,基于这些数据进行算法的建模,并用此模型对给定的输入值,预测输出。应用领域如股市预测,房价预测等。</p>
<p>无监督学习:给定一个数据即,没有人告诉你改如何处理,也不知道数据的类别,你需要依据这些
</summary>
<category term="机器学习" scheme="http://yoursite.com/categories/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/"/>
<category term="技术教程" scheme="http://yoursite.com/tags/%E6%8A%80%E6%9C%AF%E6%95%99%E7%A8%8B/"/>
</entry>
<entry>
<title>内存泄露分析</title>
<link href="http://yoursite.com/2016/07/07/%E5%86%85%E5%AD%98%E6%B3%84%E9%9C%B2%E5%88%86%E6%9E%90/"/>
<id>http://yoursite.com/2016/07/07/内存泄露分析/</id>
<published>2016-07-07T10:07:28.000Z</published>
<updated>2016-07-07T10:12:50.000Z</updated>
<content type="html"><p>内存泄露是个程序开发中经久不衰的话题,外行人看应用外观设计,内容组织方式,来判断程序做的怎样;内行人看打开开发软件,通过观察代码架构,质量以及内存变化来判断应用质量的高低。</p>
<p>因为移动端硬件设备自身的特点,内存较小,在内存的处理上尤为重要,优秀的内存处理能增加应用的流畅性,减少内存占用,提升性能,避免出现OOM异常或者是其他因对象释放而造成的程序崩溃。。</p>
<hr>
<h2 id="内存泄露的定义"><a href="#内存泄露的定义" class="headerlink" title="内存泄露的定义"></a>内存泄露的定义</h2><h2 id="定义的方式有两种"><a href="#定义的方式有两种" class="headerlink" title="定义的方式有两种"></a>定义的方式有两种</h2><p>1.所有对象的强引用都已经不存在,但是对象仍在内存中</p>
<p>2.无用对象由于强引用没有及时释放,占用内存</p>
<p>#内存泄露几种常见情况</p>
<ul>
<li><strong>嵌套类,闭包,匿名内部类引起内存泄露</strong></li>
</ul>
<p> 循环强引用是造成内存泄露的一种常见方式。无论是java还是swift,类都可以进行嵌套。内部类持有外部类的引用,可以直接访问外部类,这是优势,方便了方法的调用和值的传递,但也正是因为如此,内部类很容易造成内存泄露。当外部类持有内部类一个对象的强引用的时候,就会形成形成了循环强引用。类似的java中的匿名内部类和swift以及OC中的闭包都会捕获上下文对象的引用,当闭包的生命周期超过上下文对象应有的生命周期时就会发生暂时性的内存泄露,比如开启一个线程,在java中我们会使用一个Runnable对象,这个对象捕获了上下文对象的引用,,runnable对象不会结束,线程的任务就不结束,runnable对象对上下文对象的强引用就不会释放,上下文对象属于无用的对象就造成了内存泄露,闭包同理。如果上下文对象对runnale对象持有强引用,那么将形成循环强引用,彼此永远无法释放。<br> <br> <br> <br> iOS和Android都是单线程模型,两个平台所使用的语言中都使用runloop方式来解决事件排队问题,Android使用handler机制来做事件排队或者切换线程执行任务,当发送runnalbe任务时会造成短时间的上下文对象的内存泄露,比如我进入一个acitity活动页面,在第一个生命周期方法中使用handler向主线程发送一个runnable任务延时十秒执行,我进入页面后立即退出,观察内存可以发现activity对象并没有立即被销毁,而是过了十秒之后,当然可能是十一秒,也可能是十五秒,因为java的垃圾回收机制并不是时时刻刻都在回收的。iOS使用performSelector方法实现同样的功能,同理selector方法也会造成短时间的上下文内存泄露。<br><a id="more"></a></p>
<ul>
<li><strong>静态方法引起内存泄露</strong></li>
</ul>
<p> 静态引用持有的对象的生命周期与整个应用一样长,因此静态引用如果持有一个大额数据对象,那么造成的内存泄露是十分严重的,比如Android中的context对象,视图对象等,使用静态引用一定要谨慎,当然静态引用也能在某些情况为性能的优化做出贡献,比如多次重复性的创建同一个大内存对象,我们可以在可控的范畴里将对象定义为静态引用,避免重复创建,在适当的生命周期方法中置空静态引用就行了
</p>
<hr>
<p> 上面讨论的内存泄露情况都是每一次的操作上的内存泄露,假设一个iOS应用中的一个页面,用户进入一次就造成controller循环强引用的内存泄露,那么多次操作这种内存泄露就会累计,可以想象,如果用户重复操作页面的进入与退出,应用肯定会因为内存泄露而崩溃,因此一个优秀的应用,内存上的优化处理是十分必要的。
</p>
<p>##内存泄露的解决方案</p>
<p> 我认为对象的引用关系不能仅仅以直接引用持有关系来判定,比如A对象的成员属性中有B对象,那么我们称A对象持有B对象的引用,如果B对象中的成员属性中有C对象,那么我们称B对象持有C对象的引用,如果此时C中的成员属性有A对象,那么这三者又会形成循环强引用,一种间接的循环强引用,这种间接形成的循环强引用大多数时候是不易察觉的,因此我们所能做的是在类中持有对象引用的时候要万分注意,思考和避免强引用的形成。</p>
<p> 对象的释放是有顺序的,一个对象无法释放,这个对象内部持有的强引用的对象也将无法释放;一个对象一旦释放,那么这个对象所持有的所有引用也将释放。举个例子,比如controller对象无法释放,那么controller对象所持有的其他对象比如视图对象view,其他的一些开发者自己定义的对象都无法释放。<br>我建议持有系统组件对象比如Android的Activity,iOS的UIViewController的引用都为弱引用,唯一的强引用让系统框架自身持有,这样能很大程度避免内存泄露,这也就要求了,在使用组件对象作为代理模式中的代理对象的时候,代理对象的引用要为弱引用,我们可以翻看iOS的部分View组件的源码,比如UITableView,它的delegate和dataSource代理对象的引用都是弱引用,我们大多数时候都会将controller或者Activity作为代理,因此这样去定义代理对象的引用是十分必要的。我们经常自定义view,然后将view的相关行为方法通过接口代理出去,试想,如果view中的代理对象是强引用,并将代理对象设置为controller而自定义view在controller持有的对象view中,这就形成了间接的循环强应用,造成了内存泄露</p>
<p>尽量保证一个对象只有一个强引用,这也是解决循环强引用的方式。系统对象的引用尽量为弱引用,因为强引用在系统框架中已经有了。</p>
<p>在某些情况下,弱引用的使用能给我们的开发带来便利。我们经常需要解决一种情况,页面已经回退,但是请求仍然没有着陆在外面飞,造成了暂时性的业务逻辑对象的内存泄露;在swift中如果使用unowned self来声明不捕获业务逻辑对象有时候会造成崩溃,原因很简单,就是对象已经被回收了,但是在网络回调方法中试图调用这个对象的方法。</p>
<p>我们可以网络回调方法中使用若引用来修饰逻辑对象,在controller中使用业务对象的强引用。当页面回退后,controller对象销毁,那么业务逻辑对象的强引用也销毁ARC引用计数个数为0,业务逻辑对象销毁,网络请求回来后,若引用业务逻辑对象已经被回收,方法就不会调用,省去了很多对象非空的判断,代码也更加优雅。</p>
</content>
<summary type="html">
<p>内存泄露是个程序开发中经久不衰的话题,外行人看应用外观设计,内容组织方式,来判断程序做的怎样;内行人看打开开发软件,通过观察代码架构,质量以及内存变化来判断应用质量的高低。</p>
<p>因为移动端硬件设备自身的特点,内存较小,在内存的处理上尤为重要,优秀的内存处理能增加应用的流畅性,减少内存占用,提升性能,避免出现OOM异常或者是其他因对象释放而造成的程序崩溃。。</p>
<hr>
<h2 id="内存泄露的定义"><a href="#内存泄露的定义" class="headerlink" title="内存泄露的定义"></a>内存泄露的定义</h2><h2 id="定义的方式有两种"><a href="#定义的方式有两种" class="headerlink" title="定义的方式有两种"></a>定义的方式有两种</h2><p>1.所有对象的强引用都已经不存在,但是对象仍在内存中</p>
<p>2.无用对象由于强引用没有及时释放,占用内存</p>
<p>#内存泄露几种常见情况</p>
<ul>
<li><strong>嵌套类,闭包,匿名内部类引起内存泄露</strong></li>
</ul>
<p> 循环强引用是造成内存泄露的一种常见方式。无论是java还是swift,类都可以进行嵌套。内部类持有外部类的引用,可以直接访问外部类,这是优势,方便了方法的调用和值的传递,但也正是因为如此,内部类很容易造成内存泄露。当外部类持有内部类一个对象的强引用的时候,就会形成形成了循环强引用。类似的java中的匿名内部类和swift以及OC中的闭包都会捕获上下文对象的引用,当闭包的生命周期超过上下文对象应有的生命周期时就会发生暂时性的内存泄露,比如开启一个线程,在java中我们会使用一个Runnable对象,这个对象捕获了上下文对象的引用,,runnable对象不会结束,线程的任务就不结束,runnable对象对上下文对象的强引用就不会释放,上下文对象属于无用的对象就造成了内存泄露,闭包同理。如果上下文对象对runnale对象持有强引用,那么将形成循环强引用,彼此永远无法释放。<br> <br> <br> <br> iOS和Android都是单线程模型,两个平台所使用的语言中都使用runloop方式来解决事件排队问题,Android使用handler机制来做事件排队或者切换线程执行任务,当发送runnalbe任务时会造成短时间的上下文对象的内存泄露,比如我进入一个acitity活动页面,在第一个生命周期方法中使用handler向主线程发送一个runnable任务延时十秒执行,我进入页面后立即退出,观察内存可以发现activity对象并没有立即被销毁,而是过了十秒之后,当然可能是十一秒,也可能是十五秒,因为java的垃圾回收机制并不是时时刻刻都在回收的。iOS使用performSelector方法实现同样的功能,同理selector方法也会造成短时间的上下文内存泄露。<br>
</summary>
<category term="iOS" scheme="http://yoursite.com/categories/iOS/"/>
<category term="技术教程" scheme="http://yoursite.com/tags/%E6%8A%80%E6%9C%AF%E6%95%99%E7%A8%8B/"/>
</entry>
<entry>
<title>Cocopods高级教程</title>
<link href="http://yoursite.com/2016/05/17/Cocopods%E9%AB%98%E7%BA%A7%E6%95%99%E7%A8%8B/"/>
<id>http://yoursite.com/2016/05/17/Cocopods高级教程/</id>
<published>2016-05-17T08:59:53.000Z</published>
<updated>2016-05-17T09:16:55.000Z</updated>
<content type="html"><h2 id="cocopods安装"><a href="#cocopods安装" class="headerlink" title="cocopods安装"></a>cocopods安装</h2><p> 本教程默认Mac已经安装Ruby环境,如果没有安装Ruby,请自行搜索。 <br> 如果电脑没有安装cocopods,打开终端输入以下命令: </p>
<pre><code>$ sudo gem install cocoapods
</code></pre><p> 如果由于网络原因无法下载cocopods,那么我建议你使用淘宝镜像下载,具体的方式请自行搜索,并非本文重点。<br>如果已经安装,那么我建议你将cocopods更新到最新稳定版本,命令与上面一样。 </p>
<h2 id="使用cocopods拉取远依赖库"><a href="#使用cocopods拉取远依赖库" class="headerlink" title="使用cocopods拉取远依赖库"></a>使用cocopods拉取远依赖库</h2><p> 在拉取之前你必须确定你已经安装了cocopods。步骤如下<br><a id="more"></a></p>
<ul>
<li>创建一个新的ios项目</li>
<li>打开电脑终端窗口 <code>$ cd</code> 进入你的项目根目录</li>
<li>使用$ <code>pod init</code> 命令创建一个Podfile文件</li>
<li>第一行你应当定义你支持的平台和版本,比如<br><code>platform :ios, &#39;9.0&#39;</code></li>
<li><p>创建目标应用部分,使用 <code>target &#39;$TARGET_NAME&#39; do</code> 开头和 <code>end</code>结束,例如 </p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">target &apos;MyApp&apos; do</span><br><span class="line">pod &apos;ObjectiveSugar&apos;</span><br><span class="line">end</span><br></pre></td></tr></table></figure>
</li>
<li><p>然后保存的你Podfile文件,执行 <code>$ pod install</code> 命令,将会自动创建新文件</p>
</li>
<li>找到文件中的 <code>&#39;$TARGET_NAME&#39;.xcworkspace</code>,点击打开,这个文件将是你以后使用的项目打开文件。</li>
</ul>
<h2 id="Pod命令简介"><a href="#Pod命令简介" class="headerlink" title="Pod命令简介"></a>Pod命令简介</h2><p> 许多开始使用cocopods的新手似乎都不大能分清<code>pod install</code>和<code>pod update</code>的作用</p>
<ul>
<li><code>pod install</code>:第一次给项目安装cocopods时使用,在已经有cocopods环境的项目中添加或者删除依赖库时使用。</li>
<li><code>pod update</code>:主要是用来升级依赖库的版本,其中加上依赖库名字,比如 <code>pod update PODNAME</code>将只更新这个依赖库的版本。<br>如果装载新的依赖库速度过慢,可以使用命令<code>pod install --verbose --no-repo-update</code>来替代<code>pod install</code></li>
</ul>
<h2 id="Podfile文件"><a href="#Podfile文件" class="headerlink" title="Podfile文件"></a>Podfile文件</h2><p> 支持一个target的podfile可能是这样子的:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">target &apos;MyApp&apos; do</span><br><span class="line">pod &apos;AFNetworking&apos;, &apos;~&gt; 3.0&apos;</span><br><span class="line"> end</span><br></pre></td></tr></table></figure>
<p> 如果你有多个target,不同的target使用不同的库,互不影响,那么可能是这样子的:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">abstract_target &apos;Shows&apos; do</span><br><span class="line">pod &apos;ShowsKit&apos;</span><br><span class="line">pod &apos;Fabric&apos;</span><br><span class="line"></span><br><span class="line"># Has its own copy of ShowsKit + ShowWebAuth</span><br><span class="line">target &apos;ShowsiOS&apos; do</span><br><span class="line">pod &apos;ShowWebAuth&apos;</span><br><span class="line">end</span><br><span class="line"></span><br><span class="line"># Has its own copy of ShowsKit + ShowTVAuth</span><br><span class="line">target &apos;ShowsTV&apos; do</span><br><span class="line">pod &apos;ShowTVAuth&apos;</span><br><span class="line">end</span><br><span class="line">en</span><br></pre></td></tr></table></figure>
<h2 id="依赖库的版本"><a href="#依赖库的版本" class="headerlink" title="依赖库的版本"></a>依赖库的版本</h2><ul>
<li><p>如果你希望使用库最新的版本就那么只要:<br><code>pod &#39;SSZipArchive&#39;</code></p>
</li>
<li><p>如果你希望使用库的某个特定版本:<br><code>pod &#39;Objection&#39;, &#39;0.9&#39;</code></p>
</li>
<li><p>使用操作符来定义</p>
</li>
</ul>
<ul>
<li>‘&gt; 0.1’ 任何大于0.1的版本</li>
<li>‘&gt;= 0.1’ 任何大于或者等于0.1的版本</li>
<li>‘&lt; 0.1’ 任何小于0.1的版本</li>
<li>‘&lt;= 0.1’ 任何小于或者等于0.1的版本</li>
<li>‘~&gt; 0.1.2’ 大于等于0.1.2版本,小于0.2版本</li>
<li>‘~&gt; 0.1’ 大于等于0.1版本,小于1.0版本</li>
</ul>
<h2 id="库的路径"><a href="#库的路径" class="headerlink" title="库的路径"></a>库的路径</h2><ul>
<li><p>依赖于本地库:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">pod &apos;AFNetworking&apos;, :path =&gt; &apos;~/Documents/AFNetworking&apos;</span><br></pre></td></tr></table></figure>
</li>
<li><p>使用github上项目的master主干仓库:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">pod &apos;AFNetworking&apos;, :git =&gt; &apos;https://github.com/gowalla/AFNetworking.git&apos;</span><br></pre></td></tr></table></figure>
</li>
<li><p>使用github上项目分支仓库:</p>
</li>
</ul>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">pod &apos;AFNetworking&apos;, :git =&gt; &apos;https://github.com/gowalla/AFNetworking.git&apos;, :branch =&gt; &apos;dev&apos;</span><br></pre></td></tr></table></figure>
<ul>
<li>使用特定的tag版本仓库:</li>
</ul>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">pod &apos;AFNetworking&apos;, :git =&gt; &apos;https://github.com/gowalla/AFNetworking.git&apos;, :tag =&gt; &apos;0.7.0&apos;</span><br></pre></td></tr></table></figure>
<ul>
<li>使用某次提交的仓库:<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">pod &apos;AFNetworking&apos;, :git =&gt; &apos;https://github.com/gowalla/AFNetworking.git&apos;, :commit =&gt; &apos;082f8319af&apos;</span><br></pre></td></tr></table></figure>
</li>
</ul>
<h2 id="创建自己的cocopods依赖库"><a href="#创建自己的cocopods依赖库" class="headerlink" title="创建自己的cocopods依赖库"></a>创建自己的cocopods依赖库</h2><p> 我推荐你用官方自动生成的模板来构建自己的库项目,避免自己动手去构建的错误,比如语法错误,文件位置错误。</p>
<ul>
<li><p>选择好文件位置,创建自己的库项目</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">pod lib create MyLib</span><br></pre></td></tr></table></figure>
</li>
<li><p>期间会有些选择,根据自己的需求去打命令选择。主要有 </p>
<ul>
<li>Objective-C or Swift</li>
<li>Making a Demo Application</li>
<li>Choosing a Test Framework</li>
<li>View-based Testing</li>
</ul>
</li>
</ul>
<p>最后的目录如下:</p>
<blockquote>
<p>MyLib<br>├── .travis.yml<br>├── _Pods.xcproject<br>├── Example<br>│ ├── MyLib<br>│ ├── MyLib.xcodeproj<br>│ ├── MyLib.xcworkspace<br>│ ├── Podfile<br>│ ├── Podfile.lock<br>│ ├── Pods<br>│ └── Tests<br>├── LICENSE<br>├── MyLib.podspec<br>├── Pod<br>│ ├── Assets<br>│ └── Classes<br>│ └── RemoveMe.[swift/m]<br>└── README.md</p>
</blockquote>
<p>–<br> 这个文件中自动包含了license , readme.md , pod描述文件。你所要做的事情就是将你的代码嵌入进去,并修改 podspec中的summary描述文字,<code>&lt;GITHUB NAME&gt;</code>为你的github账户名,可选的修改和添加其他字段属性。在修改spec文件的时候要注意语法错误往往都是双引号或者单引号引起的,有的文本编辑器默认更改了了spec文件的双引号和单引号类型,你可以更正过来,一般单引号都是使用键盘上面数字1左边的的键位上的单引号,双引号可以复制其他正确引用的单引号。<br> Pod文件是你存放自己的库的地方,Example是库的使用示例代码,你可以向使用者展示下如何使用你的库。<br> 注意,如果你的库是由swift语言编写,那么你需要将需要暴露给使用者的类,接口,和方法等等声明为public,否则可能会出现访问不到该类的情况。</p>
<ul>
<li>将自己的库代码嵌入项目<br>在xcode编辑界面中,将自己的库代码放入 Development Pods文件夹,然后执行<code>pod update</code>,注意库的权限一定要是public,然后项目重新编译一下。在需要使用到库的类中导入库 <code>import ANNetworking</code> ,我建议你在自己的Example中检查下库的可用性。</li>
<li>使用git工具将项目push到自己的github仓库中</li>
<li>realse版本发布的准备<br>当你即将发布自己的库到cocopods的时候,你需要先使用命令<code>pod lib lint</code>来检查下pod描述文件是否有错误,确认无误,给你的项目打上版本tag,并且push,命令如下</li>
</ul>
<pre><code>$ git add -A &amp;&amp; git commit -m &quot;Release 0.0.1.&quot;
$ git tag &apos;0.0.1&apos;
$ git push --tags
</code></pre><ul>
<li>部署自己的库<br>在部署前先要进行错误检查,使用命令<code>pod lib lint</code>和<code>pod spec lint</code>,二者的区别在于,前者只会进行本地校验,后者进行github仓库和tag校验。</li>
<li>将pod描述文件推送到pod服务器,网络畅通情况下,一到两分钟就能看到成功的结果,命令如下:</li>
</ul>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"> pod trunk push NAME.podspec</span><br></pre></td></tr></table></figure>
<p>完成后搜索下自己传上去的库,<code>pod search NAME</code>,最好能自己试用一下。</p>
</content>
<summary type="html">
<h2 id="cocopods安装"><a href="#cocopods安装" class="headerlink" title="cocopods安装"></a>cocopods安装</h2><p> 本教程默认Mac已经安装Ruby环境,如果没有安装Ruby,请自行搜索。 <br> 如果电脑没有安装cocopods,打开终端输入以下命令: </p>
<pre><code>$ sudo gem install cocoapods
</code></pre><p> 如果由于网络原因无法下载cocopods,那么我建议你使用淘宝镜像下载,具体的方式请自行搜索,并非本文重点。<br>如果已经安装,那么我建议你将cocopods更新到最新稳定版本,命令与上面一样。 </p>
<h2 id="使用cocopods拉取远依赖库"><a href="#使用cocopods拉取远依赖库" class="headerlink" title="使用cocopods拉取远依赖库"></a>使用cocopods拉取远依赖库</h2><p> 在拉取之前你必须确定你已经安装了cocopods。步骤如下<br>
</summary>
<category term="iOS" scheme="http://yoursite.com/categories/iOS/"/>
<category term="技术教程" scheme="http://yoursite.com/tags/%E6%8A%80%E6%9C%AF%E6%95%99%E7%A8%8B/"/>
</entry>
</feed>