當前位置:首頁 » 編程軟體 » 編譯器優化過程是什麼

編譯器優化過程是什麼

發布時間: 2023-01-12 07:12:56

『壹』 編譯的優化,有尺寸和速度兩種方式,分別有什麼意義

條件編譯:
#define A
……
#if A
代碼1
#endif
說明:如果編譯器遇到最後面以#endif結尾的#if指令時,當指定的符號已經定義時,才執行#if和#endif之間的代碼。如上面的代碼,由於A已經定義,則執行編譯代碼1.若將#define A刪掉,則無視代碼1.

所謂包含文件目錄就是你安裝編譯軟體時,在安裝目錄下生成的一些目錄中,大多數會有一個include目錄,在該目錄下存放了編譯器提供的頭文件,像常見的stdio.h等頭文件。

『貳』 編譯器的編譯器優化

應用程序之所以復雜, 是由於它們具有處理多種問題以及相關數據集的能力。實際上, 一個復雜的應用程序就象許多不同功能的應用程序「 粘貼」 在一起。源文件中大部分復雜性來自於處理初始化和問題設置代碼。這些文件雖然通常占源文件的很大一部分, 具有很大難度, 但基本上不花費C PU 執行周期。
盡管存在上述情況, 大多數Makefile文件只有一套編譯器選項來編譯項目中所有的文件。因此, 標準的優化方法只是簡單地提升優化選項的強度, 一般從O 2 到O 3。這樣一來, 就需要投人大量 精力來調試, 以確定哪些文件不能被優化, 並為這些文件建立特殊的make規則。
一個更簡單但更有效的方法是通過一個性能分析器, 來運行最初的代碼, 為那些佔用了85 一95 % CPU 的源文件生成一個列表。通常情況下, 這些文件大約只佔所有文件的1%。如果開發人員立刻為每一個列表中的文件建立其各自的規則, 則會處於更靈活有效的位置。這樣一來改變優化只會引起一小部分文件被重新編譯。進而,由於時間不會浪費在優化不費時的函數上, 重編譯全部文件將會大大地加快。

『叄』 編譯器在編譯階段,究竟做哪些事情

1. 預處理首先源代碼文件(.c/.cpp)和相關頭文件(.h/.hpp)被預處理器cpp預編譯成.i文件(C++為.ii)。預處理命令為:gcc –E hello.c –o hello.i預編譯過程主要處理那些源代碼中以#開始的預編譯指令,主要處理規則如下:u 將所有的#define刪除,並且展開所有的宏定義;u 處理所有條件編譯指令,如#if,#ifdef等;u 處理#include預編譯指令,將被包含的文件插入到該預編譯指令的位置。該過程遞歸進行,及被包含的文件可能還包含其他文件。u 刪除所有的注釋//和 /**/;u 添加行號和文件標識,如#2 「hello.c」 2,以便於編譯時編譯器產生調試用的行號信息及用於編譯時產生編譯錯誤或警告時能夠顯示行號信息;u 保留所有的#pragma編譯器指令,因為編譯器須要使用它們。2. 編譯編譯過程就是把預處理完的文件進行一系列詞法分析,語法分析,語義分析及優化後生成相應的匯編代碼文件(.s)。編譯的命令為:gcc –S hello.i –o hello.s或者從源文件直接輸出匯編代碼文件:gcc –S hello.c –o hello.s現在版本的GCC把預編譯和編譯兩個步驟合並成一個步驟,由程序cc1來完成(C++為cc1plus)。3. 匯編匯編就是將匯編代碼轉變成機器可以執行的命令,生成目標文件(.o),匯編器as根據匯編指令和機器指令的對照表一一翻譯即可完成。匯編的命令為:gcc –c hello.s –o hello.o或者從源文件直接輸出目標文件:gcc –c hello.c –o hello.o4. 鏈接鏈接就是鏈接器ld將各個目標文件組裝在一起,解決符號依賴,庫依賴關系,並生成可執行文件。鏈接的命令為:ld –static crt1.o crti.o crtbeginT.o hello.o –start-group –lgcc –lgcc_eh –lc-end-group crtend.o crtn.o一般我們使用一條命令就可以完成上述4個步驟:gcc hello.c實際上gcc只是一些其它程序的包裝,它會根據不同參數去調用預編譯編譯程序cc1、匯編器as、鏈接器ld。

『肆』 C/C++的編譯器會怎樣優化

優化編譯是一個極其復雜和龐大的問題,不可能就這么說清楚。

簡單說就是凡是有辦法簡化的處理編譯器會盡可能給你簡化,凡是有辦法用SIMD並行的運算編譯器會盡量給你並行,凡是你沒用到的內容編譯器都會給你刪除。

『伍』 程序的編譯過程是怎樣的程序的解釋過程是怎樣的

編譯器首先用掃描程序掃描源代碼,然後用語法分析程序分析得到語法樹,然後經過語義分析、優化處理,最後通過代碼生成程序得到目標代碼的文件。
整個編譯過程就是(掃描-語法分析-語義分析-優化-目標代碼生成)。通常生成的是匯編代碼,機器代碼,可以直接執行,不需要解釋。
而解釋的過程只使用與解釋型語言,這種語言只編譯成一種中間文件,在運行時通過虛擬機讀取中間文件進行解釋運行。這種語言天生速度比較慢,但可以達到所謂的跨平台效果。
如果想深入了解,推薦看一看《編譯原理》,如果只是想大概了解,推薦看一看《編譯原理》的目錄~呵呵

『陸』 編譯程序的工作過程一般可以劃分為哪5個基本階段,還自始至終伴隨進行哪兩項工作

1、編譯程序把一個源程序翻譯成目標程序的工作過程分為五個階段:詞法分析;語法分析;中間代碼生成;代碼優化;目標代碼生成。

2、編譯程序的工作過程一般自始至終伴隨進行信息表管理和出錯處理兩項工作。

主要是進行詞法分析和語法分析,又稱為源程序分析,分析過程中發現有語法錯誤,給出提示信息。

(6)編譯器優化過程是什麼擴展閱讀:

解釋程序是一種語言處理程序,在詞法、語法和語義分析方面與編譯程序的工作原理基本相同,但在運行用戶程序時,它直接執行源程序或源程序的內部形式(中間代碼)。因此,解釋程序並不產生目標程序,這是它和編譯程序的主要區別。解釋程序的工作過程如下:

1、由總控程序完成初始化工作。

2、依次從源程序中取出一條語句進行語法檢查,如有錯,輸出錯誤信息;如果通過了語法檢查,則根據語句翻澤成相應的指令並執行它。

3、檢查源程序是否已經全部解釋執行完畢,如果未完成則繼續解釋並執行下一條語句,直到全部語句都處理完畢。

『柒』 java代碼優化有哪些常用的方法

1、 盡量指定類的final修飾符 帶有final修飾符的類是不可派生的。
在Java核心API中,有許多應用final的例子,例如java.lang.String。為String類指定final防止了人們覆蓋length()方法。另外,如果指定一個類為final,則該類所有的方法都是final。Java編譯器會尋找機會內聯(inline)所有的final方法(這和具體的編譯器實現有關)。此舉能夠使性能平均提高50% 。
2、 盡量重用對象。
特別是String 對象的使用中,出現字元串連接情況時應用StringBuffer 代替。由於系統不僅要花時間生成對象,以後可能還需花時間對這些對象進行垃圾回收和處理。因此,生成過多的對象將會給程序的性能帶來很大的影響。
3、 盡量使用局部變數,調用方法時傳遞的參數以及在調用中創建的臨時變數都保存在棧(Stack)中,速度較快。
其他變數,如靜態變數、實例變數等,都在堆(Heap)中創建,速度較慢。另外,依賴於具體的編譯器/JVM,局部變數還可能得到進一步優化。請參見《盡可能使用堆棧變數》。
4、 不要重復初始化變數
默認情況下,調用類的構造函數時, Java會把變數初始化成確定的值:所有的對象被設置成null,整數變數(byte、short、int、long)設置成0,float和double變數設置成0.0,邏輯值設置成false。當一個類從另一個類派生時,這一點尤其應該注意,因為用new關鍵詞創建一個對象時,構造函數鏈中的所有構造函數都會被自動調用。
5、 在JAVA + ORACLE 的應用系統開發中,java中內嵌的SQL語句盡量使用大寫的形式,以減輕ORACLE解析器的解析負擔。
6、 Java 編程過程中,進行資料庫連接、I/O流操作時務必小心,在使用完畢後,即使關閉以釋放資源。
因為對這些大對象的操作會造成系統大的開銷,稍有不慎,會導致嚴重的後果。
7、 由於JVM的有其自身的GC機制,不需要程序開發者的過多考慮,從一定程度上減輕了開發者負擔,但同時也遺漏了隱患,過分的創建對象會消耗系統的大量內存,嚴重時會導致內存泄露,因此,保證過期對象的及時回收具有重要意義。
JVM回收垃圾的條件是:對象不在被引用;然而,JVM的GC並非十分的機智,即使對象滿足了垃圾回收的條件也不一定會被立即回收。所以,建議我們在對象使用完畢,應手動置成null。
8、 在使用同步機制時,應盡量使用方法同步代替代碼塊同步。
9、 盡量減少對變數的重復計算
例如:for(int i = 0;i < list.size; i ++) {

}
應替換為:
for(int i = 0,int len = list.size();i < len; i ++){

}
10、盡量採用lazy loading 的策略,即在需要的時候才開始創建。

例如: String str = 「aaa」;
if(i == 1) {
list.add(str);
}
應替換為:
if(i == 1) {
String str = 「aaa」;
list.add(str);
}

11、慎用異常

異常對性能不利。拋出異常首先要創建一個新的對象。Throwable介面的構造函數調用名為fillInStackTrace()的本地(Native)方法,fillInStackTrace()方法檢查堆棧,收集調用跟蹤信息。只要有異常被拋出,VM就必須調整調用堆棧,因為在處理過程中創建了一個新的對象。 異常只能用於錯誤處理,不應該用來控製程序流程。
12、不要在循環中使用:

Try {
} catch() {
}
應把其放置在最外層。
13、StringBuffer 的使用:

StringBuffer表示了可變的、可寫的字元串。
有三個構造方法 :
StringBuffer (); //默認分配16個字元的空間
StringBuffer (int size); //分配size個字元的空間
StringBuffer (String str); //分配16個字元+str.length()個字元空間
你可以通過StringBuffer的構造函數來設定它的初始化容量,這樣可以明顯地提升性能。
這里提到的構造函數是StringBuffer(int length),length參數表示當前的StringBuffer能保持的字元數量。你也可以使用ensureCapacity(int minimumcapacity)方法在StringBuffer對象創建之後設置它的容量。首先我們看看StringBuffer的預設行為,然後再找出一條更好的提升性能的途徑。
StringBuffer在內部維護一個字元數組,當你使用預設的構造函數來創建StringBuffer對象的時候,因為沒有設置初始化字元長度,StringBuffer的容量被初始化為16個字元,也就是說預設容量就是16個字元。當StringBuffer達到最大容量的時候,它會將自身容量增加到當前的2倍再加2,也就是(2*舊值+2)。如果你使用預設值,初始化之後接著往裡面追加字元,在你追加到第16個字元的時候它會將容量增加到34(2*16+2),當追加到34個字元的時候就會將容量增加到70(2*34+2)。無論何事只要StringBuffer到達它的最大容量它就不得不創建一個新的字元數組然後重新將舊字元和新字元都拷貝一遍――這也太昂貴了點。所以總是給StringBuffer設置一個合理的初始化容量值是錯不了的,這樣會帶來立竿見影的性能增益。StringBuffer初始化過程的調整的作用由此可見一斑。所以,使用一個合適的容量值來初始化StringBuffer永遠都是一個最佳的建議。
14、合理的使用Java類 java.util.Vector。

簡單地說,一個Vector就是一個java.lang.Object實例的數組。Vector與數組相似,它的元素可以通過整數形式的索引訪問。但是,Vector類型的對象在創建之後,對象的大小能夠根據元素的增加或者刪除而擴展、縮小。請考慮下面這個向Vector加入元素的例子:
Object bj = new Object();
Vector v = new Vector(100000);
for(int I=0;
I<100000; I++) { v.add(0,obj); }
除非有絕對充足的理由要求每次都把新元素插入到Vector的前面,否則上面的代碼對性能不利。在默認構造函數中,Vector的初始存儲能力是10個元素,如果新元素加入時存儲能力不足,則以後存儲能力每次加倍。Vector類就對象StringBuffer類一樣,每次擴展存儲能力時,所有現有的元素都要復制到新的存儲空間之中。下面的代碼片段要比前面的例子快幾個數量級:
Object bj = new Object();
Vector v = new Vector(100000);
for(int I=0; I<100000; I++) { v.add(obj); }
同樣的規則也適用於Vector類的remove()方法。由於Vector中各個元素之間不能含有「空隙」,刪除除最後一個元素之外的任意其他元素都導致被刪除元素之後的元素向前移動。也就是說,從Vector刪除最後一個元素要比刪除第一個元素「開銷」低好幾倍。
假設要從前面的Vector刪除所有元素,我們可以使用這種代碼:
for(int I=0; I<100000; I++)
{
v.remove(0);
}
但是,與下面的代碼相比,前面的代碼要慢幾個數量級:
for(int I=0; I<100000; I++)
{
v.remove(v.size()-1);
}
從Vector類型的對象v刪除所有元素的最好方法是:
v.removeAllElements();
假設Vector類型的對象v包含字元串「Hello」。考慮下面的代碼,它要從這個Vector中刪除「Hello」字元串:
String s = "Hello";
int i = v.indexOf(s);
if(I != -1) v.remove(s);
這些代碼看起來沒什麼錯誤,但它同樣對性能不利。在這段代碼中,indexOf()方法對v進行順序搜索尋找字元串「Hello」,remove(s)方法也要進行同樣的順序搜索。改進之後的版本是:
String s = "Hello";
int i = v.indexOf(s);
if(I != -1) v.remove(i);
這個版本中我們直接在remove()方法中給出待刪除元素的精確索引位置,從而避免了第二次搜索。一個更好的版本是:
String s = "Hello"; v.remove(s);
最後,我們再來看一個有關Vector類的代碼片段:
for(int I=0; I++;I < v.length)
如果v包含100,000個元素,這個代碼片段將調用v.size()方法100,000次。雖然size方法是一個簡單的方法,但它仍舊需要一次方法調用的開銷,至少JVM需要為它配置以及清除堆棧環境。在這里,for循環內部的代碼不會以任何方式修改Vector類型對象v的大小,因此上面的代碼最好改寫成下面這種形式:
int size = v.size(); for(int I=0; I++;I<size)
雖然這是一個簡單的改動,但它仍舊贏得了性能。畢竟,每一個CPU周期都是寶貴的。
15、當復制大量數據時,使用System.array()命令。
int[] src={1,3,5,6,7,8};
int[] dest = new int[6];
System.array(src, 0, dest, 0, 6);
src:源數組; srcPos:源數組要復制的起始位置;
dest:目的數組; destPos:目的數組放置的起始位置;
length:復制的長度.
注意:src and dest都必須是同類型或者可以進行轉換類型的數組.
16、代碼重構:增強代碼的可讀性。
public class ShopCart {
private List carts ;

public void add (Object item) {
if(carts == null) {
carts = new ArrayList();
}
crts.add(item);
}
public void remove(Object item) {
if(carts. contains(item)) {
carts.remove(item);
}
}
public List getCarts() {
//返回只讀列表
return Collections.unmodifiableList(carts);
}

//不推薦這種方式
//this.getCarts().add(item);
}
17、不用new關鍵詞創建類的實例

用new關鍵詞創建類的實例時,構造函數鏈中的所有構造函數都會被自動調用。但如果一個對象實現了Cloneable介面,我們可以調用它的clone()方法。clone()方法不會調用任何類構造函數。
在使用設計模式(Design Pattern)的場合,如果用Factory模式創建對象,則改用clone()方法創建新的對象實例非常簡單。例如,下面是Factory模式的一個典型實現:
public static Credit getNewCredit() {
return new Credit();
}
改進後的代碼使用clone()方法,如下所示:
private static Credit BaseCredit = new Credit();
public static Credit getNewCredit() {
return (Credit) BaseCredit.clone();
}
上面的思路對於數組處理同樣很有用。
18、乘法和除法

考慮下面的代碼:
for (val = 0; val < 100000; val +=5) {
alterX = val * 8; myResult = val * 2;
}
用移位操作替代乘法操作可以極大地提高性能。下面是修改後的代碼:
for (val = 0; val < 100000; val += 5) {
alterX = val << 3; myResult = val << 1;
}
修改後的代碼不再做乘以8的操作,而是改用等價的左移3位操作,每左移1位相當於乘以2。相應地,右移1位操作相當於除以2。值得一提的是,雖然移位操作速度快,但可能使代碼比較難於理解,所以最好加上一些注釋。
19、在JSP頁面中關閉無用的會話。

一個常見的誤解是以為session在有客戶端訪問時就被創建,然而事實是直到某server端程序調用HttpServletRequest.getSession(true)這樣的語句時才被創建,注意如果JSP沒有顯示的使用 <> 關閉session,則JSP文件在編譯成Servlet時將會自動加上這樣一條語句HttpSession session = HttpServletRequest.getSession(true);這也是JSP中隱含的session對象的來歷。由於session會消耗內存資源,因此,如果不打算使用session,應該在所有的JSP中關閉它。
對於那些無需跟蹤會話狀態的頁面,關閉自動創建的會話可以節省一些資源。使用如下page指令:<%@ page session="false"%>
20、JDBC與I/O

如果應用程序需要訪問一個規模很大的數據集,則應當考慮使用塊提取方式。默認情況下,JDBC每次提取32行數據。舉例來說,假設我們要遍歷一個5000行的記錄集,JDBC必須調用資料庫157次才能提取到全部數據。如果把塊大小改成512,則調用資料庫的次數將減少到10次。
21、Servlet與內存使用
許多開發者隨意地把大量信息保存到用戶會話之中。一些時候,保存在會話中的對象沒有及時地被垃圾回收機制回收。從性能上看,典型的症狀是用戶感到系統周期性地變慢,卻又不能把原因歸於任何一個具體的組件。如果監視JVM的堆空間,它的表現是內存佔用不正常地大起大落。
解決這類內存問題主要有二種辦法。第一種辦法是,在所有作用范圍為會話的Bean中實現HttpSessionBindingListener介面。這樣,只要實現valueUnbound()方法,就可以顯式地釋放Bean使用的資源。
另外一種辦法就是盡快地把會話作廢。大多數應用伺服器都有設置會話作廢間隔時間的選項。另外,也可以用編程的方式調用會話的setMaxInactiveInterval()方法,該方法用來設定在作廢會話之前,Servlet容器允許的客戶請求的最大間隔時間,以秒計。
22、使用緩沖標記

一些應用伺服器加入了面向JSP的緩沖標記功能。例如,BEA的WebLogic Server從6.0版本開始支持這個功能,Open Symphony工程也同樣支持這個功能。JSP緩沖標記既能夠緩沖頁面片斷,也能夠緩沖整個頁面。當JSP頁面執行時,如果目標片斷已經在緩沖之中,則生成該片斷的代碼就不用再執行。頁面級緩沖捕獲對指定URL的請求,並緩沖整個結果頁面。對於購物籃、目錄以及門戶網站的主頁來說,這個功能極其有用。對於這類應用,頁面級緩沖能夠保存頁面執行的結果,供後繼請求使用。
23、選擇合適的引用機制

在典型的JSP應用系統中,頁頭、頁腳部分往往被抽取出來,然後根據需要引入頁頭、頁腳。當前,在JSP頁面中引入外部資源的方法主要有兩種:include指令,以及include動作。
include指令:例如<%@ include file="right.html" %>。該指令在編譯時引入指定的資源。在編譯之前,帶有include指令的頁面和指定的資源被合並成一個文件。被引用的外部資源在編譯時就確定,比運行時才確定資源更高效。
include動作:例如<jsp:include page="right.jsp" />。該動作引入指定頁面執行後生成的結果。由於它在運行時完成,因此對輸出結果的控制更加靈活。但時,只有當被引用的內容頻繁地改變時,或者在對主頁面的請求沒有出現之前,被引用的頁面無法確定時,使用include動作才合算。
24、及時清除不再需要的會話

為了清除不再活動的會話,許多應用伺服器都有默認的會話超時時間,一般為30分鍾。當應用伺服器需要保存更多會話時,如果內存容量不足,操作系統會把部分內存數據轉移到磁碟,應用伺服器也可能根據「最近最頻繁使用」(Most Recently Used)演算法把部分不活躍的會話轉儲到磁碟,甚至可能拋出「內存不足」異常。在大規模系統中,串列化會話的代價是很昂貴的。當會話不再需要時,應當及時調用HttpSession.invalidate()方法清除會話。HttpSession.invalidate()方法通常可以在應用的退出頁面調用。
25、不要將數組聲明為:public static final 。
26、HashMap的遍歷效率討論

經常遇到對HashMap中的key和value值對的遍歷操作,有如下兩種方法:
Map<String, String[]> paraMap = new HashMap<String, String[]>();
//第一個循環
Set<String> appFieldDefIds = paraMap.keySet();
for (String appFieldDefId : appFieldDefIds) {
String[] values = paraMap.get(appFieldDefId);
......
}

//第二個循環
for(Entry<String, String[]> entry : paraMap.entrySet()){
String appFieldDefId = entry.getKey();
String[] values = entry.getValue();
.......
}
第一種實現明顯的效率不如第二種實現。
分析如下 Set<String> appFieldDefIds = paraMap.keySet(); 是先從HashMap中取得keySet
代碼如下:
public Set<K> keySet() {
Set<K> ks = keySet;
return (ks != null ? ks : (keySet = new KeySet()));
}

private class KeySet extends AbstractSet<K> {
public Iterator<K> iterator() {
return newKeyIterator();
}
public int size() {
return size;
}
public boolean contains(Object o) {
return containsKey(o);
}
public boolean remove(Object o) {
return HashMap.this.removeEntryForKey(o) != null;
}
public void clear() {
HashMap.this.clear();
}
}
其實就是返回一個私有類KeySet, 它是從AbstractSet繼承而來,實現了Set介面。
再來看看for/in循環的語法
for(declaration : expression)
statement
在執行階段被翻譯成如下各式
for(Iterator<E> #i = (expression).iterator(); #i.hashNext();){
declaration = #i.next();
statement
}
因此在第一個for語句for (String appFieldDefId : appFieldDefIds) 中調用了HashMap.keySet().iterator()
而這個方法調用了newKeyIterator()
Iterator<K> newKeyIterator() {
return new KeyIterator();
}
private class KeyIterator extends HashIterator<K> {
public K next() {
return nextEntry().getKey();
}
}
所以在for中還是調用了
在第二個循環for(Entry<String, String[]> entry : paraMap.entrySet())中使用的Iterator是如下的一個內部

private class EntryIterator extends HashIterator<Map.Entry<K,V>> {
public Map.Entry<K,V> next() {
return nextEntry();
}
}
此時第一個循環得到key,第二個循環得到HashMap的Entry效率就是從循環裡面體現出來的第二個循環此致可以直接取key和value值而第一個循環還是得再利用HashMap的get(Object key)來取value值現在看看HashMap的get(Object key)方法
public V get(Object key) {
Object k = maskNull(key);
int hash = hash(k);
int i = indexFor(hash, table.length); //Entry[] table
Entry<K,V> e = table;
while (true) {
if (e == null)
return null;
if (e.hash == hash && eq(k, e.key))
return e.value;
e = e.next;
}
}
其實就是再次利用Hash值取出相應的Entry做比較得到結果,所以使用第一中循環相當於兩次進入HashMap的Entry
中而第二個循環取得Entry的值之後直接取key和value,效率比第一個循環高。其實按照Map的概念來看也應該是用第二個循環好一點,它本來就是key和value的值對,將key和value分開操作在這里不是個好選擇。
27、array(數組) 和 ArryList的使用

array([]):最高效;但是其容量固定且無法動態改變;
ArrayList:容量可動態增長;但犧牲效率;
基於效率和類型檢驗,應盡可能使用array,無法確定數組大小時才使用ArrayList!
ArrayList是Array的復雜版本
ArrayList內部封裝了一個Object類型的數組,從一般的意義來說,它和數組沒有本質的差別,甚至於ArrayList的許多方法,如Index、IndexOf、Contains、Sort等都是在內部數組的基礎上直接調用Array的對應方法。
ArrayList存入對象時,拋棄類型信息,所有對象屏蔽為Object,編譯時不檢查類型,但是運行時會報錯。
註:jdk5中加入了對泛型的支持,已經可以在使用ArrayList時進行類型檢查。
從這一點上看來,ArrayList與數組的區別主要就是由於動態增容的效率問題了
28、盡量使用HashMap 和ArrayList ,除非必要,否則不推薦使用HashTable和Vector ,後者由於使用同步機制,而導致了性能的開銷。
29、StringBuffer 和StringBuilder的區別:

java.lang.StringBuffer線程安全的可變字元序列。一個類似於 String 的字元串緩沖區,但不能修改。
StringBuilder。與該類相比,通常應該優先使用 java.lang.StringBuilder類,因為它支持所有相同的操作,但由於它不執行同步,所以速度更快。為了獲得更好的性能,在構造 StirngBuffer 或 StirngBuilder 時應盡可能指定它的容量。當然,如果你操作的字元串長度不超過 16 個字元就不用了。 相同情況下使用 StirngBuilder 相比使用 StringBuffer 僅能獲得 10%-15% 左右的性能提升,但卻要冒多線程不安全的風險。而在現實的模塊化編程中,負責某一模塊的程序員不一定能清晰地判斷該模塊是否會放入多線程的環境中運行,因此:除非你能確定你的系統的瓶頸是在 StringBuffer 上,並且確定你的模塊不會運行在多線程模式下,否則還是用 StringBuffer 吧。
30、盡量避免使用split
除非是必須的,否則應該避免使用split,split由於支持正則表達式,所以效率比較低,如果是頻繁的幾十,幾百萬的調用將會耗費大量資源,如果確實需要頻繁的調用split,可以考慮使用apache的 StringUtils.split(string,char),頻繁split的可以緩存結果。
其他補充:
1、及時清除不再使用的對象,設為null
2、盡可能使用final,static等關鍵字
3、盡可能使用buffered對象
如何優化代碼使JAVA源文件及編譯後CLASS文件更小
1 盡量使用繼承,繼承的方法越多,你要寫的代碼量也就越少
2 打開JAVA編譯器的優化選項: javac -O 這個選項將刪除掉CLASS文件中的行號,並能把
一些private, static,final的小段方法申明為inline方法調用
3 把公用的代碼提取出來
4 不要初始化很大的數組,盡管初始化一個數組在JAVA代碼中只是一行的代碼量,但
編譯後的代碼是一行代碼插入一個數組的元素,所以如果你有大量的數據需要存在數組
中的話,可以先把這些數據放在String中,然後在運行期把字元串解析到數組中
5 日期類型的對象會佔用很大的空間,如果你要存儲大量的日期對象,可以考慮把它存儲為
long型,然後在使用的時候轉換為Date類型
6 類名,方法名和變數名盡量使用簡短的名字,可以考慮使用Hashjava, Jobe, Obfuscate and Jshrink等工具自動完成這個工作
7 將static final類型的變數定義到Interface中去
8 算術運算 能用左移/右移的運算就不要用*和/運算,相同的運算不要運算多次
2. 不要兩次初始化變數
Java通過調用獨特的類構造器默認地初始化變數為一個已知的值。所有的對象被設置成null,integers (byte, short, int, long)被設置成0,float和double設置成0.0,Boolean變數設置成false。這對那些擴展自其它類的類尤其重要,這跟使用一個新的關鍵詞創建一個對象時所有一連串的構造器被自動調用一樣。
3. 在任何可能的地方讓類為Final
標記為final的類不能被擴展。在《核心Java API》中有大量這個技術的例子,諸如java.lang.String。將String類標記為final阻止了開發者創建他們自己實現的長度方法。
更深入點說,如果類是final的,所有類的方法也是final的。Java編譯器可能會內聯所有的方法(這依賴於編譯器的實現)。在我的測試里,我已經看到性能平均增加了50%。
9. 異常在需要拋出的地方拋出,try catch能整合就整合
try {
some.method1(); // Difficult for javac
} catch( method1Exception e ) { // and the JVM runtime
// Handle exception 1 // to optimize this
} // code
try {
some.method2();
} catch( method2Exception e ) {
// Handle exception 2
}

try {
some.method3();
} catch( method3Exception e ) {
// Handle exception 3
}
已下代碼 更容易被編譯器優化
try {
some.method1(); // Easier to optimize
some.method2();
some.method3();
} catch( method1Exception e ) {
// Handle exception 1
} catch( method2Exception e ) {
// Handle exception 2
} catch( method3Exception e ) {
// Handle exception 3
}
10. For循環的優化
Replace…
for( int i = 0; i < collection.size(); i++ ) {
...
}
with…
for( int i = 0, n = collection.size(); i < n; i++ ) {
...
}

5、 在JAVA + ORACLE 的應用系統開發中,java中內嵌的SQL語句盡量使用大寫的形式,以減輕ORACLE解析器的解析負擔。
10、盡量採用lazy loading 的策略,即在需要的時候才開始創建。
例如: String str = 「aaa」;
if(i == 1) {
list.add(str);
}
應替換為:
if(i == 1) {
String str = 「aaa」;
list.add(str);
}
12、不要在循環中使用:
Try {
} catch() {
}
應把其放置在最外層

『捌』 簡單描述編譯的幾個處理步驟

編譯過程分為分析和綜合兩個部分,並進一步劃分為詞法分析、語法分析、語義分析、代碼優化、存儲分配和代碼生成等六個相繼的邏輯步驟。這六個步驟只表示編譯程序各部分之間的邏輯聯系,而不是時間關系。

編譯過程既可以按照這六個邏輯步驟順序地執行,也可以按照平行互鎖方式去執行。在確定編譯程序的具體結構時,常常分若干遍實現。對於源程序或中間語言程序,從頭到尾掃視一次並實現所規定的工作稱作一遍。每一遍可以完成一個或相連幾個邏輯步驟的工作。

(8)編譯器優化過程是什麼擴展閱讀:

對於c編譯程序來說,其語言的特點如下:

1、c語言是一種結構化語言。它層次清晰,便於按模塊化方式組織程序,易於調試和維護,而且表現能力和處理能力極強。

2、c語言具有豐富的運算符和數據類型,便於實現各類復雜的數據結構。它還可以直接訪問內存的物理地址,進行位(bit)一級的操作。

3、由於c語言實現了對硬體的編程操作,因此集高級語言和低級語言的功能於一體。它既可用於系統軟體的開發,也適合於應用軟體的開發。

4、此外,c語言還具有效率高、可移植性強等特點。因此它廣泛地移植到了各類各型計算機上,從而形成了多種版本。

『玖』 java編譯器的代碼優化問題

理論上的就不說了,你自己搜也能搜到很多。
舉個例子,你從一個方法a調用了另一個方法b。
我們知道,在a和b之中是可以創建相同名稱的變數的,比如都有int i = 0;這句話。這種現象的根本原因在於,方法的調用會產生中斷,中斷產生後,cpu會做現場保護,包括把變數等進行壓棧操作,即把方法a的相關資源進行了壓棧,而方法b的相關資源放在棧頂,只有棧頂資源可以與cpu交互(就把方法a中的變數i保護起來),當方法b結束後出棧,a就又回到了棧頂,並獲取了方法b運行的結果,然後繼續運行。

哎,有些啰嗦了。方法的調用、中斷、壓棧出棧等等這些操作你說一點不消耗資源吧,那是不可能的,多少都會消耗一些,雖然很非常十分微不足道。那麼編譯器的優化過程,我知道的其作用之一,就是會把這些做一個優化。原本方法a一共10句話,你偏要只寫1句,然後第2句寫成方法b,第3句寫成方法c。。。。。,然後依次嵌套調用。這樣的源代碼,編譯器優化後,就跟你直接寫10句是一個結果,即做了一定程度上的優化。

『拾』 C語言文件的編譯與執行的四個階段並分別描述

開發C程序有四個步驟:編輯、編譯、連接和運行。

任何一個體系結構處理器上都可以使用C語言程序,只要該體系結構處理器有相應的C語言編譯器和庫,那麼C源代碼就可以編譯並連接到目標二進制文件上運行。

1、預處理:導入源程序並保存(C文件)。

2、編譯:將源程序轉換為目標文件(Obj文件)。

3、鏈接:將目標文件生成為可執行文件(EXE文件)。

4、運行:執行,獲取運行結果的EXE文件。

(10)編譯器優化過程是什麼擴展閱讀:

將C語言代碼分為程序的幾個階段:

1、首先,源代碼文件測試。以及相關的頭文件,比如stdio。H、由預處理器CPP預處理為.I文件。預編譯的。文件不包含任何宏定義,因為所有宏都已展開,並且包含的文件已插入。我歸檔。

2、編譯過程是對預處理文件進行詞法分析、語法分析、語義分析和優化,生成相應的匯編代碼文件。這個過程往往是整個程序的核心部分,也是最復雜的部分之一。

3、匯編程序不直接輸出可執行文件,而是輸出目標文件。匯編程序可以調用LD來生成可以運行的可執行程序。也就是說,您需要鏈接大量的文件才能獲得「a.out」,即最終的可執行文件。

4、在鏈接過程中,需要重新調整其他目標文件中定義的函數調用指令,而其他目標文件中定義的變數也存在同樣的問題。

熱點內容
java返回this 發布:2025-10-20 08:28:16 瀏覽:593
製作腳本網站 發布:2025-10-20 08:17:34 瀏覽:888
python中的init方法 發布:2025-10-20 08:17:33 瀏覽:582
圖案密碼什麼意思 發布:2025-10-20 08:16:56 瀏覽:765
怎麼清理微信視頻緩存 發布:2025-10-20 08:12:37 瀏覽:684
c語言編譯器怎麼看執行過程 發布:2025-10-20 08:00:32 瀏覽:1013
郵箱如何填寫發信伺服器 發布:2025-10-20 07:45:27 瀏覽:255
shell腳本入門案例 發布:2025-10-20 07:44:45 瀏覽:114
怎麼上傳照片瀏覽上傳 發布:2025-10-20 07:44:03 瀏覽:806
python股票數據獲取 發布:2025-10-20 07:39:44 瀏覽:713