本文目錄一覽:
- 1、PHP的演算法可以實現大數據分析嗎
- 2、PHP滑動拼圖驗證碼的圖片是怎樣生成的
- 3、Bitmap 究竟佔多大內存
- 4、怎樣將bitmap添加到mysql資料庫中
- 5、怎麼防止imagecreatefromjpeg內存溢出
PHP的演算法可以實現大數據分析嗎
1.Bloom filter
適用範圍:可以用來實現數據字典,進行數據的判重,或者集合求交集
基本原理及要點:
對於原理來說很簡單,位數組+k個獨立hash函數。將hash函數對應的值的位數組置1,查找時如果發現所有hash函數對應位都是1說明存在,很明顯這個過程並不保證查找的結果是100%正確的。同時也不支持刪除一個已經插入的關鍵字,因為該關鍵字對應的位會牽動到其他的關鍵字。所以一個簡單的改進就是 counting Bloom filter,用一個counter數組代替位數組,就可以支持刪除了。
還有一個比較重要的問題,如何根據輸入元素個數n,確定位數組m的大小及hash函數個數。當hash函數個數k=(ln2)*(m/n)時錯誤率最小。在錯誤率不大於E的情況下,m至少要等於n*lg(1/E)才能表示任意n個元素的集合。但m還應該更大些,因為還要保證bit數組裡至少一半為 0,則m 應該=nlg(1/E)*lge 大概就是nlg(1/E)1.44倍(lg表示以2為底的對數)。
舉個例子我們假設錯誤率為0.01,則此時m應大概是n的13倍。這樣k大概是8個。
注意這裡m與n的單位不同,m是bit為單位,而n則是以元素個數為單位(準確的說是不同元素的個數)。通常單個元素的長度都是有很多bit的。所以使用bloom filter內存上通常都是節省的。
擴展:
Bloom filter將集合中的元素映射到位數組中,用k(k為哈希函數個數)個映射位是否全1表示元素在不在這個集合中。Counting bloom filter(CBF)將位數組中的每一位擴展為一個counter,從而支持了元素的刪除操作。Spectral Bloom Filter(SBF)將其與集合元素的出現次數關聯。SBF採用counter中的最小值來近似表示元素的出現頻率。
問題實例:給你A,B兩個文件,各存放50億條URL,每條URL佔用64位元組,內存限制是4G,讓你找出A,B文件共同的URL。如果是三個乃至n個文件呢?
根據這個問題我們來計算下內存的佔用,4G=2^32大概是40億*8大概是340億,n=50億,如果按出錯率0.01算需要的大概是650億個 bit。現在可用的是340億,相差並不多,這樣可能會使出錯率上升些。另外如果這些urlip是一一對應的,就可以轉換成ip,則大大簡單了。
2.Hashing
適用範圍:快速查找,刪除的基本數據結構,通常需要總數據量可以放入內存
基本原理及要點:
hash函數選擇,針對字元串,整數,排列,具體相應的hash方法。
碰撞處理,一種是open hashing,也稱為拉鏈法;另一種就是closed hashing,也稱開地址法,opened addressing。 ()
擴展:
d-left hashing中的d是多個的意思,我們先簡化這個問題,看一看2-left hashing。2-left hashing指的是將一個哈希表分成長度相等的兩半,分別叫做T1和T2,給T1和T2分別配備一個哈希函數,h1和h2。在存儲一個新的key時,同時用兩個哈希函數進行計算,得出兩個地址h1[key]和h2[key]。這時需要檢查T1中的h1[key]位置和T2中的h2[key]位置,哪一個位置已經存儲的(有碰撞的)key比較多,然後將新key存儲在負載少的位置。如果兩邊一樣多,比如兩個位置都為空或者都存儲了一個key,就把新key 存儲在左邊的T1子表中,2-left也由此而來。在查找一個key時,必須進行兩次hash,同時查找兩個位置。
問題實例:
1).海量日誌數據,提取出某日訪問百度次數最多的那個IP。
IP的數目還是有限的,最多2^32個,所以可以考慮使用hash將ip直接存入內存,然後進行統計。
3.bit-map
適用範圍:可進行數據的快速查找,判重,刪除,一般來說數據範圍是int的10倍以下
基本原理及要點:使用bit數組來表示某些元素是否存在,比如8位電話號碼
擴展:bloom filter可以看做是對bit-map的擴展
問題實例:
1)已知某個文件內包含一些電話號碼,每個號碼為8位數字,統計不同號碼的個數。
8位最多99 999 999,大概需要99m個bit,大概10幾m位元組的內存即可。
2)2.5億個整數中找出不重複的整數的個數,內存空間不足以容納這2.5億個整數。
將bit-map擴展一下,用2bit表示一個數即可,0表示未出現,1表示出現一次,2表示出現2次及以上。或者我們不用2bit來進行表示,我們用兩個bit-map即可模擬實現這個2bit-map。
4.堆
適用範圍:海量數據前n大,並且n比較小,堆可以放入內存
基本原理及要點:最大堆求前n小,最小堆求前n大。方法,比如求前n小,我們比較當前元素與最大堆里的最大元素,如果它小於最大元素,則應該替換那個最大元素。這樣最後得到的n個元素就是最小的n個。適合大數據量,求前n小,n的大小比較小的情況,這樣可以掃描一遍即可得到所有的前n元素,效率很高。
擴展:雙堆,一個最大堆與一個最小堆結合,可以用來維護中位數。
問題實例:
1)100w個數中找最大的前100個數。
用一個100個元素大小的最小堆即可。
5.雙層桶劃分 —-其實本質上就是【分而治之】的思想,重在「分」的技巧上!
適用範圍:第k大,中位數,不重複或重複的數字
基本原理及要點:因為元素範圍很大,不能利用直接定址表,所以通過多次劃分,逐步確定範圍,然後最後在一個可以接受的範圍內進行。可以通過多次縮小,雙層只是一個例子。
擴展:
問題實例:
1).2.5億個整數中找出不重複的整數的個數,內存空間不足以容納這2.5億個整數。
有點像鴿巢原理,整數個數為2^32,也就是,我們可以將這2^32個數,劃分為2^8個區域(比如用單個文件代表一個區域),然後將數據分離到不同的區域,然後不同的區域在利用bitmap就可以直接解決了。也就是說只要有足夠的磁碟空間,就可以很方便的解決。
2).5億個int找它們的中位數。
這個例子比上面那個更明顯。首先我們將int劃分為2^16個區域,然後讀取數據統計落到各個區域里的數的個數,之後我們根據統計結果就可以判斷中位數落到那個區域,同時知道這個區域中的第幾大數剛好是中位數。然後第二次掃描我們只統計落在這個區域中的那些數就可以了。
實際上,如果不是int是int64,我們可以經過3次這樣的劃分即可降低到可以接受的程度。即可以先將int64分成2^24個區域,然後確定區域的第幾大數,在將該區域分成2^20個子區域,然後確定是子區域的第幾大數,然後子區域里的數的個數只有2^20,就可以直接利用direct addr table進行統計了。
6.資料庫索引
適用範圍:大數據量的增刪改查
基本原理及要點:利用數據的設計實現方法,對海量數據的增刪改查進行處理。
擴展:
問題實例:
7.倒排索引(Inverted index)
適用範圍:搜索引擎,關鍵字查詢
基本原理及要點:為何叫倒排索引?一種索引方法,被用來存儲在全文搜索下某個單詞在一個文檔或者一組文檔中的存儲位置的映射。
以英文為例,下面是要被索引的文本:
T0 = “it is what it is”
T1 = “what is it”
T2 = “it is a banana”
我們就能得到下面的反向文件索引:
“a”: {2}
“banana”: {2}
“is”: {0, 1, 2}
“it”: {0, 1, 2}
“what”: {0, 1}
檢索的條件”what”, “is” 和 “it” 將對應集合的交集。
正向索引開發出來用來存儲每個文檔的單詞的列表。正向索引的查詢往往滿足每個文檔有序頻繁的全文查詢和每個單詞在校驗文檔中的驗證這樣的查詢。在正向索引中,文檔佔據了中心的位置,每個文檔指向了一個它所包含的索引項的序列。也就是說文檔指向了它包含的那些單詞,而反向索引則是單詞指向了包含它的文檔,很容易看到這個反向的關係。
擴展:
問題實例:文檔檢索系統,查詢那些文件包含了某單詞,比如常見的學術論文的關鍵字搜索。
8.外排序
適用範圍:大數據的排序,去重
基本原理及要點:外排序的歸併方法,置換選擇 敗者樹原理,最優歸併樹
擴展:
問題實例:
1).有一個1G大小的一個文件,裡面每一行是一個詞,詞的大小不超過16個位元組,內存限制大小是1M。返回頻數最高的100個詞。
這個數據具有很明顯的特點,詞的大小為16個位元組,但是內存只有1m做hash有些不夠,所以可以用來排序。內存可以當輸入緩衝區使用。
9.trie樹
適用範圍:數據量大,重複多,但是數據種類小可以放入內存
基本原理及要點:實現方式,節點孩子的表示方式
擴展:壓縮實現。
問題實例:
1).有10個文件,每個文件1G, 每個文件的每一行都存放的是用戶的query,每個文件的query都可能重複。要你按照query的頻度排序 。
2).1000萬字元串,其中有些是相同的(重複),需要把重複的全部去掉,保留沒有重複的字元串。請問怎麼設計和實現?
3).尋找熱門查詢:查詢串的重複度比較高,雖然總數是1千萬,但如果除去重複後,不超過3百萬個,每個不超過255位元組。
10.分散式處理 mapreduce
適用範圍:數據量大,但是數據種類小可以放入內存
基本原理及要點:將數據交給不同的機器去處理,數據劃分,結果歸約。
擴展:
問題實例:
1).The canonical example application of MapReduce is a process to count the appearances of
each different word in a set of documents:
void map(String name, String document):
// name: document name
// document: document contents
for each word w in document:
EmitIntermediate(w, 1);
void reduce(String word, Iterator partialCounts):
// key: a word
// values: a list of aggregated partial counts
int result = 0;
for each v in partialCounts:
result += ParseInt(v);
Emit(result);
Here, each document is split in words, and each word is counted initially with a “1” value by
the Map function, using the word as the result key. The framework puts together all the pairs
with the same key and feeds them to the same call to Reduce, thus this function just needs to
sum all of its input values to find the total appearances of that word.
2).海量數據分布在100台電腦中,想個辦法高效統計出這批數據的TOP10。
3).一共有N個機器,每個機器上有N個數。每個機器最多存O(N)個數並對它們操作。如何找到N^2個數的中數(median)?
經典問題分析
上千萬or億數據(有重複),統計其中出現次數最多的前N個數據,分兩種情況:可一次讀入內存,不可一次讀入。
可用思路:trie樹+堆,資料庫索引,劃分子集分別統計,hash,分散式計算,近似統計,外排序
所謂的是否能一次讀入內存,實際上應該指去除重複後的數據量。如果去重後數據可以放入內存,我們可以為數據建立字典,比如通過 map,hashmap,trie,然後直接進行統計即可。當然在更新每條數據的出現次數的時候,我們可以利用一個堆來維護出現次數最多的前N個數據,當然這樣導致維護次數增加,不如完全統計後在求前N大效率高。
如果數據無法放入內存。一方面我們可以考慮上面的字典方法能否被改進以適應這種情形,可以做的改變就是將字典存放到硬碟上,而不是內存,這可以參考資料庫的存儲方法。
當然還有更好的方法,就是可以採用分散式計算,基本上就是map-reduce過程,首先可以根據數據值或者把數據hash(md5)後的值,將數據按照範圍劃分到不同的機子,最好可以讓數據劃分後可以一次讀入內存,這樣不同的機子負責處理各種的數值範圍,實際上就是map。得到結果後,各個機子只需拿出各自的出現次數最多的前N個數據,然後匯總,選出所有的數據中出現次數最多的前N個數據,這實際上就是reduce過程。
實際上可能想直接將數據均分到不同的機子上進行處理,這樣是無法得到正確的解的。因為一個數據可能被均分到不同的機子上,而另一個則可能完全聚集到一個機子上,同時還可能存在具有相同數目的數據。比如我們要找出現次數最多的前100個,我們將1000萬的數據分布到10台機器上,找到每台出現次數最多的前 100個,歸併之後這樣不能保證找到真正的第100個,因為比如出現次數最多的第100個可能有1萬個,但是它被分到了10台機子,這樣在每台上只有1千個,假設這些機子排名在1000個之前的那些都是單獨分布在一台機子上的,比如有1001個,這樣本來具有1萬個的這個就會被淘汰,即使我們讓每台機子選出出現次數最多的1000個再歸併,仍然會出錯,因為可能存在大量個數為1001個的發生聚集。因此不能將數據隨便均分到不同機子上,而是要根據hash 後的值將它們映射到不同的機子上處理,讓不同的機器處理一個數值範圍。
而外排序的方法會消耗大量的IO,效率不會很高。而上面的分散式方法,也可以用於單機版本,也就是將總的數據根據值的範圍,劃分成多個不同的子文件,然後逐個處理。處理完畢之後再對這些單詞的及其出現頻率進行一個歸併。實際上就可以利用一個外排序的歸併過程。
另外還可以考慮近似計算,也就是我們可以通過結合自然語言屬性,只將那些真正實際中出現最多的那些詞作為一個字典,使得這個規模可以放入內存。
PHP滑動拼圖驗證碼的圖片是怎樣生成的
1 如果放在項目中用,驗證碼圖片希望可以是介面返回。ImageView以及其子類支持花式載入圖片。
2 繼承自ImageView,繪製圖片本身不用我們干預,也不用我們操心scaleType,節省很多工作。
* 在onSizeChanged()方法中生成 和 控制項寬高相關的屬性值:
1 初始化時隨機生成驗證碼區域起點
2 生成驗證碼區域Path
3 生成滑塊Bitmap
* onDraw()時,依次繪製:
1 驗證碼陰影
2 滑塊
Bitmap 究竟佔多大內存
最近在做一款塔防遊戲,用的事surfaceview框架,由於圖片過多,而且遊戲過程中都需要這些圖片,所以載入成bitmap後造成OOM(outofmemory)異常。下面是我一步一步找解決此問題的紀錄,再此分享,希望對以後出現此問題的開發者有所幫助。第一:出現問題,我的測試手機是2。2android操作系統,不會出現oom問題,但是在老闆的android4.2上卻出現了問題,因為是oom,所以我首先想到的是手動改變手機的內存大小限制。網上有些帖子說可以通過函數設置應用的HEAPSIZE來解決這個問題,其實是不對的。VMRuntime.getRuntime().setMinimumHeapSize(NewSize);堆(HEAP)是VM中佔用內存最多的部分,通常是動態分配的。堆的大小不是一成不變的,通常有一個分配機制來控制它的大小。比如初始的HEAP是4M大,當4M的空間被佔用超過75%的時候,重新分配堆為8M大;當8M被佔用超過75%,分配堆為16M大。倒過來,當16M的堆利用不足30%的時候,縮減它的大小為8M大。重新設置堆的大小,尤其是壓縮,一般會涉及到內存的拷貝,所以變更堆的大小對效率有不良影響。MaxHeapSize,是堆內存的上限值,Android的預設值是16M(某些機型是24M),對於普通應用這是不能改的。函數setMinimumHeapSize其實只是改變了堆的下限值,它可以防止過於頻繁的堆內存分配,當設置最小堆內存大小超過上限值時仍然採用堆的上限值,對於內存不足沒什麼作用。setTargetHeapUtilization(floatnewTarget)可以設定內存利用率的百分比,當實際的利用率偏離這個百分比的時候,虛擬機會在GC的時候調整堆內存大小,讓實際佔用率向個百分比靠攏。在手機上進行了多次測試,確實不好使,在此,我斷了改變內存限制的方法。第二:查找出現問題的原因。1,在網上搜索bitmap內存溢出,找到很多說是因為圖片大小引起的此問題。觀察我的資源文件,沒有太大的圖片,只是圖片數量過多,有將近900張,分別找出一張最大的圖片和幾張比較大的圖片,單獨測試,沒有發現問題。方法1排除。2,既然圖片數量過多,突破點可能就是圖片數量問題。於是分別找了200,400,600圖片進行測試,在500左右的時候遇到錯誤,通過寶哥知道了將小圖片整合存放到一張大圖的方法,以此來減少圖片的數量,但是仔細想想,載入成bitmap的時候還是要切割成小圖生成bitmap,所以對此方法表示懷疑。由於以前沒用過此方法,試試也無妨。所用到的工具是gdx—texturepackger,它只是一個工具,這裡就不多說了。測試的最終結果是還是oom。方法2排除。3,現在看來,既然不是圖片數量的問題,而且會在500張左右的時候報錯,那就可能是佔用內存大小的問題了,Android手機有內存限制,但是我的圖片大小又大於這個限制,這讓我頭疼了很長時間,研究國外的一些文章,從中發現了一些有用的信息,這些信息能夠加深你對Android的解析bitmap機制的理解,在此分享:AsofHoneycombBitmapdataisallocatedintheVMheap.作為蜂窩點陣圖數據是在VM分配堆。)ThereisareferencetoitintheVMheap(whichissmall),buttheactualdataisallocatedintheNativeheapbytheunderlyingSkiagraphicslibrary.有一個引用在VM堆(小),但實際的數據是在本機堆分配由底層Skia圖形庫。Unfortunately,whilethedefinitionofBitmapFactory.decode…()saysthatitreturnsnulliftheimagedatacouldnotbedecoded,theSkiaimplementation(orrathertheJNIgluebetweentheJavacodeandSkia)logsthemessageyou』reseeing(「VMwon』tletusallocatexxxxbytes」)andthenthrowsanOutOfMemoryexceptionwiththemisleadingmessage「bitmapsizeexceedsVMbudget」.不幸的是,雖然BitmapFactory.decode的定義…()表示,它返回null如果圖像數據不能解碼,Skia實現(或者說JNI膠之間的Java代碼和Skia)日誌消息你看到(「VM不會讓我們分配xxxx位元組」),然後拋出一個OutOfMemory異常與誤導信息」點陣圖的大小超過VM預算」。TheissueisnotintheVMheapbutisratherintheNativeheap.這個問題不是在VM堆而是在本機堆。TheNatïveheapissharedbetweenrunningapplications,sotheamountoffreespacedependsonwhatotherapplicationsarerunningandtheirbitmapusage.本機堆是正在運行的應用程序之間共享,因此空閑空間的大小取決於其他運行程序,他們使用的點陣圖。However,IhavefoundthatgetNativeHeapFreeSize()andgetNativeHeapSize()arenotreliable.然而,我發現getNativeHeapFreeSize()和getNativeHeapSize()是不可靠的。TheNativeheapsizevariesbyplatform.本機堆大小不同的平台。Soatstartup,wecheckthemaximumallowedVMheapsizetodeterminethemaximumallowedNativeheapsize.所以在啟動時,我們檢查最大允許VM堆大小來確定最大允許本機堆大小。「BitmapdataisnotallocatedintheVMheap」—itisallocatedontheVMheapasofHoneycomb「點陣圖數據不是在VM分配堆」——這是VM分配的堆在蜂窩Yes.是的。AsofHoneycomb(v3.0),bitmapdataisallocatedontheVMheap.作為蜂窩(v3.0),點陣圖數據堆上分配VM。SoalloftheaboveonlyappliestoGingerbread(v2.3.x)andbefore所以所有上述只適用於薑餅(v23x)和之前這些信息零零散散,但是不難發現,問題的原因就在於根據Android版本的不同,bitmapdata存放的位置是不同的,3.0以前是分配在nativeheap上,3.0以後是分配在VMheap上。
怎樣將bitmap添加到mysql資料庫中
MySQL 原生並不支持 bitmap 類型,所以就只能存字元串,然後就根據你的 bitmap 長度以及轉換方式來選擇是用什麼類型來存儲,處理的過程在代碼層面完成。
我簡單說下我們做同樣的事情的做法,不一定是好方法,可以一起探討。
首先,我們操作資料庫的語言是 PHP。使用的是 ASCII 表裡的 0 ~ 127位的字元,所以每一個字元可以存 8bits,然後用一個 char(125) 來存 bitmap 的一個片段,每個片段可以存 1000bits。
通過 PHP 計算某一位在那一個片段的第幾位,例如 2345,就在第三個片段的第345位(從1開始的話),然後通過 PHP 進行更新。當然,也可以直接用 SQL 更新,SQL 語句寫起來比較麻煩,我寫了半天才寫出來:
unhex( conv( bin( conv( hex( STR1 ), 16, 10 ) | conv( hex( STR2 ), 16, 10 ) ), 2, 16 ) )
不過我們用 MySQL 存儲也就是為了確保數據的安全性,大部分的查詢操作都在 redis 裡面完成,redis 原生支持 bitmap 用起來又高效又方便。
怎麼防止imagecreatefromjpeg內存溢出
盡量不要使用setImageBitmap或setImageResource或BitmapFactory.decodeResource來設置一張大圖,
因為這些函數在完成decode後,最終都是通過java層的createBitmap來完成的,需要消耗更多內存。
因此,改用先通過BitmapFactory.decodeStream方法,創建出一個bitmap,再將其設為ImageView的 source,
decodeStream最大的秘密在於其直接調用JNInativeDecodeAsset()來完成decode,
無需再使用java層的createBitmap,從而節省了java層的空間。
如果在讀取時加上圖片的Config參數,可以跟有效減少載入的內存,從而跟有效阻止拋out of Memory異常
另外,decodeStream直接拿的圖片來讀取位元組碼了, 不會根據機器的各種解析度來自動適應,
使用了decodeStream之後,需要在hdpi和mdpi,ldpi中配置相應的圖片資源,
否則在不同解析度機器上都是同樣大小(像素點數量),顯示出來的大小就不對了。
另外,以下方式也大有幫助:
1. InputStream is = this.getResources().openRawResource(R.drawable.pic1);
BitmapFactory.Options options=new BitmapFactory.Options();
options.inJustDecodeBounds = false;
options.inSampleSize = 10; //width,hight設為原來的十分一
Bitmap btp =BitmapFactory.decodeStream(is,null,options);
2. if(!bmp.isRecycle() ){
bmp.recycle() //回收圖片所佔的內存
system.gc() //提醒系統及時回收
}
以下奉上一個方法:
Java代碼
1. /**
2. * 以最省內存的方式讀取本地資源的圖片
3. * @param context
4. * @param resId
5. * @return
6. */
7. public static Bitmap readBitMap(Context context, int resId){
8. BitmapFactory.Options opt = new BitmapFactory.Options();
9. opt.inPreferredConfig = Bitmap.Config.RGB_565;
10. opt.inPurgeable = true;
11. opt.inInputShareable = true;
12. //獲取資源圖片
13. InputStream is = context.getResources().openRawResource(resId);
14. return BitmapFactory.decodeStream(is,null,opt);
15. }
================================================================================
Android內存溢出的解決辦法
轉自:
昨天在模擬器上給gallery放入圖片的時候,出現java.lang.OutOfMemoryError: bitmap size exceeds VM budget 異常,圖像大小超過了RAM內存。
模擬器RAM比較小,只有8M內存,當我放入的大量的圖片(每個100多K左右),就出現上面的原因。
由於每張圖片先前是壓縮的情況,放入到Bitmap的時候,大小會變大,導致超出RAM內存,具體解決辦法如下:
//解決載入圖片 內存溢出的問題
//Options 只保存圖片尺寸大小,不保存圖片到內存
BitmapFactory.Options opts = new BitmapFactory.Options();
//縮放的比例,縮放是很難按準備的比例進行縮放的,其值表明縮放的倍數,SDK中建議其值是2的指數值,值越大會導致圖片不清晰
opts.inSampleSize = 4;
Bitmap bmp = null;
bmp = BitmapFactory.decodeResource(getResources(), mImageIds[position],opts);
…
//回收
bmp.recycle();
通過上面的方式解決了,但是這並不是最完美的解決方式。
通過一些了解,得知如下:
優化Dalvik虛擬機的堆內存分配
對於Android平台來說,其託管層使用的Dalvik Java VM從目前的表現來看還有很多地方可以優化處理,比如我們在開發一些大型遊戲或耗資源的應用中可能考慮手動干涉GC處理,使用 dalvik.system.VMRuntime類提供的setTargetHeapUtilization方法可以增強程序堆內存的處理效率。當然具體原理我們可以參考開源工程,這裡我們僅說下使用方法: private final static float TARGET_HEAP_UTILIZATION = 0.75f; 在程序onCreate時就可以調用 VMRuntime.getRuntime().setTargetHeapUtilization(TARGET_HEAP_UTILIZATION); 即可。
Android堆內存也可自己定義大小
對於一些Android項目,影響性能瓶頸的主要是Android自己內存管理機制問題,目前手機廠商對RAM都比較吝嗇,對於軟體的流暢性來說RAM對性能的影響十分敏感,除了 優化Dalvik虛擬機的堆內存分配外,我們還可以強制定義自己軟體的對內存大小,我們使用Dalvik提供的 dalvik.system.VMRuntime類來設置最小堆內存為例:
private final static int CWJ_HEAP_SIZE = 6* 1024* 1024 ;
VMRuntime.getRuntime().setMinimumHeapSize(CWJ_HEAP_SIZE); //設置最小heap內存為6MB大小。當然對於內存吃緊來說還可以通過手動干涉GC去處理
bitmap 設置圖片尺寸,避免 內存溢出 OutOfMemoryError的優化方法
★android 中用bitmap 時很容易內存溢出,報如下錯誤:Java.lang.OutOfMemoryError : bitmap size exceeds VM budget
● 主要是加上這段:
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 2;
● eg1:(通過Uri取圖片)
private ImageView preview;
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 2;//圖片寬高都為原來的二分之一,即圖片為原來的四分之一
Bitmap bitmap = BitmapFactory.decodeStream(cr
.openInputStream(uri), null, options);
preview.setImageBitmap(bitmap);
以上代碼可以優化內存溢出,但它只是改變圖片大小,並不能徹底解決內存溢出。
● eg2:(通過路徑去圖片)
private ImageView preview;
private String fileName= “/sdcard/DCIM/Camera/2010-05-14 16.01.44.jpg”;
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 2;//圖片寬高都為原來的二分之一,即圖片為原來的四分之一
Bitmap b = BitmapFactory.decodeFile(fileName, options);
preview.setImageBitmap(b);
filePath.setText(fileName);
★Android 還有一些性能優化的方法:
● 首先內存方面,可以參考 Android堆內存也可自己定義大小 和 優化Dalvik虛擬機的堆內存分配
● 基礎類型上,因為Java沒有實際的指針,在敏感運算方面還是要藉助NDK來完成。Android123提示遊戲開發者,這點比較有意思的是Google 推出NDK可能是幫助遊戲開發人員,比如OpenGL ES的支持有明顯的改觀,本地代碼操作圖形界面是很必要的。
● 圖形對象優化,這裡要說的是Android上的Bitmap對象銷毀,可以藉助recycle()方法顯示讓GC回收一個Bitmap對象,通常對一個不用的Bitmap可以使用下面的方式,如
if(bitmapObject.isRecycled()==false) //如果沒有回收
bitmapObject.recycle();
● 目前系統對動畫支持比較弱智對於常規應用的補間過渡效果可以,但是對於遊戲而言一般的美工可能習慣了GIF方式的統一處理,目前Android系統僅能預覽GIF的第一幀,可以藉助J2ME中通過線程和自己寫解析器的方式來讀取GIF89格式的資源。
● 對於大多數Android手機沒有過多的物理按鍵可能我們需要想像下了做好手勢識別 GestureDetector 和重力感應來實現操控。通常我們還要考慮誤操作問題的降噪處理。
Android堆內存也可自己定義大小
對於一些大型Android項目或遊戲來說在演算法處理上沒有問題外,影響性能瓶頸的主要是Android自己內存管理機制問題,目前手機廠商對RAM都比較吝嗇,對於軟體的流暢性來說RAM對性能的影響十分敏感,除了上次Android開發網提到的優化Dalvik虛擬機的堆內存分配外,我們還可以強制定義自己軟體的對內存大小,我們使用Dalvik提供的 dalvik.system.VMRuntime類來設置最小堆內存為例:
private final static int CWJ_HEAP_SIZE = 6* 1024* 1024 ;
VMRuntime.getRuntime().setMinimumHeapSize(CWJ_HEAP_SIZE); //設置最小heap內存為6MB大小。當然對於內存吃緊來說還可以通過手動干涉GC去處理,我們將在下次提到具體應用。
優化Dalvik虛擬機的堆內存分配
對於Android平台來說,其託管層使用的Dalvik JavaVM從目前的表現來看還有很多地方可以優化處理,比如我們在開發一些大型遊戲或耗資源的應用中可能考慮手動干涉GC處理,使用 dalvik.system.VMRuntime類提供的setTargetHeapUtilization方法可以增強程序堆內存的處理效率。當然具體原理我們可以參考開源工程,這裡我們僅說下使用方法: private final static floatTARGET_HEAP_UTILIZATION = 0.75f; 在程序onCreate時就可以調用 VMRuntime.getRuntime().setTargetHeapUtilization(TARGET_HEAP_UTILIZATION); 即可。
介紹一下圖片佔用進程的內存演算法吧。
android中處理圖片的基礎類是Bitmap,顧名思義,就是點陣圖。佔用內存的演算法如下:
圖片的width*height*Config。
如果Config設置為ARGB_8888,那麼上面的Config就是4。一張480*320的圖片佔用的內存就是480*320*4 byte。
前面有人說了一下8M的概念,其實是在默認情況下android進程的內存佔用量為16M,因為Bitmap他除了java中持有數據外,底層C++的 skia圖形庫還會持有一個SKBitmap對象,因此一般圖片佔用內存推薦大小應該不超過8M。這個可以調整,編譯源代碼時可以設置參數。
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/244904.html