開發(fā)出高質(zhì)量的系統(tǒng)
posted on 2007-02-11 03:26 dreamstone 閱讀(2075) 評論(27) 編輯 收藏 所屬分類: jdk相關(guān)
最開始的測試是在Eclipse中測試的,怕是eclipse的問題,在控制臺(tái)下也做了測試,雖然得到的數(shù)字有微小偏差,但依然是方法一比方法二快1秒左右。問題繼續(xù)。。 回復(fù) 更多評論
據(jù)說是因?yàn)榫植孔兞糠旁诙褩V械脑颉?nbsp; 回復(fù) 更多評論
在我的機(jī)器上測試,兩者可以看作是一樣快的。對每一個(gè)方法運(yùn)行多次,結(jié)果也會(huì)稍有偏差,第一個(gè)方法:3375(次數(shù)比較多)、3390。 第二個(gè)方法:3375(次數(shù)比較多)、3390、3391、3406。 對于下面2段代碼來說: for (int i=0;i<n;i++){ String str = // } String str = null; for(int i=0;i<n;i++){ str = // } 區(qū)別只是str變量的作用域不同---意味著:代碼1的str變量的偏移位置在出了循環(huán)的作用域以后,可以被分配給下一個(gè)出現(xiàn)的局部變量,而代碼2str的位置會(huì)一直占有,直到方法結(jié)束。 之所以,有人感覺代碼2快,我想是一種錯(cuò)覺吧,就是以為代碼1會(huì)在循環(huán)中重復(fù)聲明變量str--實(shí)際上不是這樣。 另外,JLS是什么東東? 回復(fù) 更多評論
to:JonneyQuest 詳細(xì)說說? 回復(fù) 更多評論
to:daydream 你怎么運(yùn)行的,不是兩個(gè)一塊調(diào)用的吧,如果是用循環(huán)多次調(diào)用求平均值,活著兩個(gè)一塊調(diào)用是不準(zhǔn)的。如果你是循環(huán)調(diào)用,活著同時(shí)調(diào)用,你可以把兩個(gè)函數(shù)的調(diào)用順序換一下,會(huì)有較大的差距。 JLS=The Java Language Specification 講述的是Java語言的特性,很多東西C++和Java是不同的,JLS中有描述。例如lazyloading的單態(tài)在Java中是不可實(shí)現(xiàn)的,這個(gè)就因?yàn)镴ava的優(yōu)化造成的,通過JLS可以查到。 回復(fù) 更多評論
沒有,我是分開運(yùn)行的,直接運(yùn)行你的代碼。 回復(fù) 更多評論
這里問題大了。創(chuàng)建對象第一忌:不要在循環(huán)體中創(chuàng)建對象。這種做法會(huì)在內(nèi)存中保存N份這個(gè)對象的引用會(huì)浪費(fèi)大量的內(nèi)存空間(雖說內(nèi)存便宜,可以進(jìn)行硬件升級),同時(shí)JVM的GC機(jī)制會(huì)因?yàn)檫@些無謂的對象做大量的回收工作,系統(tǒng)不慢都不行呀 ......................................................................................... 很簡單的一個(gè)道理,你用String對象根本看不出效果。如果你換成個(gè)自定義對象或者圖形對象呢?你的第一種做法會(huì)在堆內(nèi)存中生成大量的垃圾對象,這些對象首先占用內(nèi)存,二則在對于速度的影響上它不會(huì)馬上體現(xiàn)出來(畢竟在內(nèi)存夠用的情況下無法體現(xiàn)),一旦堆內(nèi)存中的eden area滿了,GC機(jī)制開始起作用了那么你就會(huì)覺得你的程序速度狂降。。。。 所以說,第二種做法才是王道! 呵呵,剛剛寫了一篇關(guān)于java優(yōu)化編程的文字,希望可以提供幫助 http://www.tkk7.com/sinoly/archive/2007/02/11/99205.html 回復(fù) 更多評論
相對而言,性能的影響并不只是這段代碼的執(zhí)行速度。需要考慮在JVM種它的處理方式,以及這種方式對資源占用的情況。很多性能問題都是在日積月累中體現(xiàn)的。只是丂一條語句所謂的執(zhí)行速度來判斷效率,個(gè)人感覺很不合理 回復(fù) 更多評論
to sinoly : “創(chuàng)建對象第一忌:不要在循環(huán)體中創(chuàng)建對象。這種做法會(huì)在內(nèi)存中保存N份這個(gè)對象的引用會(huì)浪費(fèi)大量的內(nèi)存空間” 這是誤解。完全沒有在內(nèi)存中保存N份對象的引用,循環(huán)體內(nèi)聲明的對象也只是在java棧中占據(jù)一個(gè)位置。 反而在循環(huán)體內(nèi)聲明的對象因?yàn)槠渥饔糜蛑皇窃谘h(huán)體內(nèi),更節(jié)約內(nèi)存(雖然微乎其微)。 回復(fù) 更多評論
to:sinoly 我在平時(shí)寫代碼的時(shí)候也不是在循環(huán)體內(nèi)創(chuàng)建,但是記憶中差別不大。 對于你的說法, 1,String看不出效果,自定義對象和圖形對象能有效果? 在印象中無論是什么,這里保留的都是一個(gè)引用,應(yīng)該是一樣大的。所以應(yīng)該沒有對象和圖形的差別。而且第一種做法不會(huì)產(chǎn)生垃圾對象,只會(huì)出現(xiàn)大量的引用。一個(gè)引用占用的內(nèi)存是很小的,不會(huì)是大量的。但是如果循環(huán)次數(shù)很多,也是可觀的,所以我平時(shí)也是寫在循環(huán)體之外。 2,如果寫在外邊,其實(shí)并不一定就快,因?yàn)樵诶镞厡懙脑掃^了循環(huán)體就過了它的有效范圍,可以被回收了,雖然并不一定立即回收,但如果第二種寫法對象則不能回收。恰恰相反,如果對象很大,例如圖形控件,活著保存大量數(shù)據(jù)的Bean,這個(gè)時(shí)候這個(gè)對象要到函數(shù)結(jié)束才會(huì)被回收,如果函數(shù)體很長,活著函數(shù)的執(zhí)行時(shí)間很長,那么這個(gè)才是更消耗內(nèi)存的。所以說哪種寫法要看情況而定。 3,如何判定一個(gè)程序的好壞?這個(gè)是個(gè)綜合問題,要考慮很多因素,但是在印象種無論如何方法二應(yīng)該是比方法一快的,結(jié)果剛好相反,開啟這個(gè)帖子主要是為了這個(gè)問題。就是為什么會(huì)這樣?而不是討論哪個(gè)方法更好。 回復(fù) 更多評論
java字節(jié)碼中,對于每一個(gè)方法都有一個(gè)max_locals屬性,指出方法的局部變量所需要的存儲(chǔ)空間(以字為單位)。 對于一樓的例子,如果把 String str = // 移到循環(huán)體外,則max_locals會(huì)比在循環(huán)體內(nèi)更大。 回復(fù) 更多評論
to:sinoly 看了你寫的關(guān)于對象創(chuàng)建的問題,我們說的不是一個(gè)問題啊。 你的問題是:在循環(huán)體種創(chuàng)建相同的對象,就是作用一樣的對象,這個(gè)當(dāng)然是浪費(fèi)內(nèi)存了。這種問題不需要再討論。 我的問題是這樣的,并不再創(chuàng)建對象上,例如,如下問題,從List種取出對象,可以有兩種寫法, List<Object> list= //...一個(gè)已經(jīng)存在的List 方法一 for(int i=0;i<list.size();i++){ Object obj = list.get(i); } 方法二 Object obj= null; for(int i=0;i<list.size();i++){ obj= list.get(i); } 這個(gè)里邊根本沒有創(chuàng)建對象的問題,有的問題是方法一會(huì)多很多引用,方法二會(huì)讓一個(gè)引用保存期很長,同時(shí)對象有效期也變的很長。(其實(shí)你的性能優(yōu)化的文章種應(yīng)該指出這個(gè)問題的。) 另外提示一下,對于我第一個(gè)例子中寫的: for (int i=0;i<n;i++){ String str = ""; } 在這個(gè)函數(shù)中只會(huì)創(chuàng)建一個(gè)對象,因?yàn)镾tring是非可變對象,虛擬機(jī)會(huì)自動(dòng)重用,這個(gè)你可以參照一下JLS中的解釋。只有這種情況才是浪費(fèi) for (int i=0;i<n;i++){ String str = new String(""); } 最后感謝你參與,另外提一點(diǎn)建議: 1,回文或者寫文章前應(yīng)該先確認(rèn)一下自己的觀點(diǎn)是否是對的,最好給出證明,雖然確認(rèn)了也不能保證一定是對的,但是至少做過了,這是一種態(tài)度。我也是一直這么要求自己,無論多么簡單的問題,都給出一個(gè)思考的過程,因?yàn)檫@樣對看文章的人有幫助。例如你上邊說到的,如果是自定義對象活著圖形對象的觀點(diǎn),剛好是錯(cuò)誤的證明,你可以這樣試試。虛擬機(jī)內(nèi)存設(shè)置64M,如果你在List中取出一個(gè)60M的對象,然后在循環(huán)之后再new一個(gè)10M的對象,方法一是可以運(yùn)行的,雖然說慢,但方法二就OutOfMemory了。除非你在循環(huán)之后設(shè)置 變量= null,但這種做法是否更好只得商榷. 最后說明一點(diǎn),應(yīng)用開發(fā)和底層框架開發(fā)其實(shí)有很多東西是不同的。如果實(shí)際負(fù)責(zé)過項(xiàng)目就了解的。 回復(fù) 更多評論
@daydream 謝謝再次回復(fù),想問一下關(guān)于max_locals這個(gè)屬性, 1,為什么放到循環(huán)體外反而會(huì)更大呢?能給簡單講一下為什么嗎?活著給一個(gè)能查到原因的方向。 2,另外這個(gè)max_locals變大后為什么會(huì)影響性能呢?在什么時(shí)候會(huì)使用到max_locals這個(gè)屬性呢? 謝謝 回復(fù) 更多評論
對下面2個(gè)方法,foo1需要的max_locals是4,foo2是5, foo1需要的4大概是:this變量占1個(gè)字、方法參數(shù)x占1個(gè)字、 第一段循環(huán)的時(shí)候,變量i占一個(gè)字、s1占一個(gè)字,第二個(gè)循環(huán)的時(shí)候,i、s1已經(jīng)超出作用域,所以,變量j、s2占用了和i、s1重疊的空間,所以最多需要4個(gè)字就夠了。 foo2方法中s1的作用域直到方法結(jié)束,所以需要5個(gè)字長度。 max_locals變大后應(yīng)該不會(huì)影響到性能,但是我這兒的意思是說,將局部變量放在循環(huán)體內(nèi)聲明并不會(huì)導(dǎo)致性能下降。 void foo1(int x) { for (int i = 0; i < 1000; i++) { String s1 = "..."; } for (int j = 0; j < 1000; j++) { String s2 = "...."; } } void foo2(int x) { String s1 = "..."; for (int i = 0; i < 1000; i++) { // other code..... } for (int j = 0; j < 1000; j++) { String s2 = "...."; } } 回復(fù) 更多評論
另外,將局部變量放在循環(huán)體內(nèi)聲明,也不會(huì)導(dǎo)致多出來很多引用。 因?yàn)椋植孔兞繉?yīng)于java棧的偏移是在編譯時(shí)就確定的,并不是在運(yùn)行期動(dòng)態(tài)分配的。循環(huán)體內(nèi)的局部變量對應(yīng)的是同一個(gè)偏移位置。 回復(fù) 更多評論
另外,max_locals只是編譯器在編譯時(shí)確定,存放在字節(jié)碼中,供JVM在運(yùn)行期調(diào)用方法時(shí)分配java棧幀大小用的,對于程序員應(yīng)該沒什么用,因?yàn)槌绦蛞矝]辦法訪問java棧。 回復(fù) 更多評論
現(xiàn)在大概明白了max_locals的作用,但是我這測試出的問題還在。不知道為什么第一個(gè)方法要比第二個(gè)方法快。 回復(fù) 更多評論
另外我看你上邊寫的用我的代碼,測試結(jié)果是接近的,可我怎么測都是差距一秒啊,你的運(yùn)行環(huán)境 ? 我是xp下,試過eclipse運(yùn)行,試過直接控制臺(tái)用java命令運(yùn)行。 jdk1.5 回復(fù) 更多評論
運(yùn)行你的第二段測試代碼: 先運(yùn)行test1共5次,結(jié)果:3406、3453、3391、3453、3391 然后把代碼改成test2,運(yùn)行5次,結(jié)果: 3406、3406、3406、3437、3391 運(yùn)行環(huán)境:XP、512M內(nèi)存、Eclipse3.2下,JDK6.0,沒有加啟動(dòng)參數(shù),默認(rèn)最大內(nèi)存好像是64M。 回復(fù) 更多評論
郁悶了,我的兩臺(tái)電腦,測試的結(jié)果都是穩(wěn)定的差不到1秒 xp sp2 eclipse3.2.1 jdk1.5 啟動(dòng)參數(shù)也沒加,最大內(nèi)存開始是512,后來改成256和64都試了。 結(jié)果test1:2938 2953 2954 2954 2969 test2:3797 3797 3781 4000 3797 3797 我今天再找別人試一下,看看什么情況。 回復(fù) 更多評論
又找了幾個(gè)同事幫忙測試了一下,果然,有的差距是100毫秒,有的200,有的基本沒差距。我公司的電腦差距是200,也就是說我家里的測試不準(zhǔn)確,真實(shí)不可思議,我在家測了很多次,都穩(wěn)定在差距1000毫秒,呵呵。不過問題總算解決了。 另外經(jīng)過測試發(fā)現(xiàn)在這個(gè)問題上,amd的cpu比intel的快,單核的比雙核的快。。有意思。 回復(fù) 更多評論
注意jdk版本,一些基本的東西隨著JDK不斷的更新,都會(huì)有改變。對JAVA沒什么好印象! 回復(fù) 更多評論
有些是跟版本有關(guān)的,這個(gè)跟版本沒關(guān)系,呵呵。 為什么對java印象不好呢,每個(gè)語言都有它的好處和壞處。 回復(fù) 更多評論
剛才又做了個(gè)測試,一個(gè)很有意思的結(jié)果:使用ibm的ibm_sdk50測試結(jié)果剛好相反,執(zhí)行10億次,方法二比方法一快了200毫秒。挺有意思。 不過結(jié)論是一樣的,就是兩種方法性能差別很小,但方法二讓對象的有效期變長了,如果是大對象(例如圖形對象,數(shù)據(jù)bean對象)則不好,所以一般情況下應(yīng)選擇方法一的寫法?;蛘叻椒ǘ膶懛由鲜謩?dòng)清空釋放對象。 回復(fù) 更多評論
牛??! 俺可很少關(guān)注到這一層。俺通常來說會(huì)用第一種的??梢允∠掳?300ms寫代碼的時(shí)間。 回復(fù) 更多評論
我在你的代碼中分別添加了如下代碼: public static void test1(long n){ for (int i=0;i<n;i++){ String str = ""; } System.gc(); } public static void test2(long n){ String str = null; for (int i=0;i<n;i++){ str = ""; } System.gc(); } 測試結(jié)果分別為: test1: 3787, 3710, 3756, 3616, 3523 test2: 3538, 3678, 3507, 3756, 3460 我的觀點(diǎn)與sinoly一致! 回復(fù) 更多評論
@coffey 你一定是沒看完評論,可以看看我回復(fù)sinoly的評論,你就知道為什么了。 很多東西不要想當(dāng)然,要測試、分析。只有理論上和實(shí)踐上都通過才是正確地。否則一定是有錯(cuò)誤的地方。 回復(fù) 更多評論
Powered by: BlogJava Copyright © dreamstone