即時編譯器概念
⑴ jvm中線程本地內存是真實存在的,還是一個抽象概念
jvm內存模型:java代碼是運行在Java虛擬機之上的,由Java虛擬機通過解釋執行(解釋器)或編譯執行(即時編譯器)來完成,故Java內存模型,也就是指Java虛擬機的運行時內存模型。
運行時內存模型,分為線程私有和共享數據區兩大類,其中線程私有的數據區包含程序計數器、虛擬機棧、本地方法區,所有線程共享的數據區包含Java堆、方法區,在方法區內有一個常量池。java運行時的內存模型圖,如下:
從圖中,可知內存分為線程私有和共享兩大類:
(1)線程私有區,包含以下3類:
程序計數器,記錄正在執行的虛擬機位元組碼的地址;
虛擬機棧:方法執行的內存區,每個方法執行時會在虛擬機棧中創建棧幀;
本地方法棧:虛擬機的Native方法執行的內存區;
(2)線程共享區,包含以下2類
Java堆:對象分配內存的區域;
方法區:存放類信息、常量、靜態變數、編譯器編譯後的代碼等數據;
常量池:存放編譯器生成的各種字面量和符號引用,是方法區的一部分。
樓主提到的Java棧,一般而言是指圖中的虛擬機棧,在代碼中的方法調用過程中,往往需要從一個方法跳轉到另一個方法,執行完再返回,那麼在跳轉之前需要在當前方法的基本信息壓入棧中保存再跳轉。
三、關於寄存器的問題
對於java最常用的虛擬機,sun公司提供的hotspot虛擬機,是基於棧的虛擬機;而對於android的虛擬機,則採用google提供的dalvik,art兩種虛擬機,在android 5.0以後便默認採用art虛擬機,這是基於寄存器的虛擬機。 樓主問的是jvm(即java vm),這是基於棧的虛擬機。那麼關於虛擬機棧,這塊內存的內容,我們再進一步詳細分析,如下圖:
可以看到,在虛擬機棧有一幀幀的 棧幀組成,而棧幀包含局部變數表,操作棧等子項,那麼線程在運行的時候,代碼在運行時,是通過程序計數器不斷執行下一條指令。真正指令運算等操作時通過控制操作棧的操作數入棧和出棧,將操作數在局部變數表和操作棧之間轉移。
⑵ java 靜態變數和靜態常量
靜態變數是屬於靜態存儲方式,但是屬於靜態存儲方式的量不一定就是靜態變數,例如外部變數雖屬於靜態存儲巧配搭方式,但不一定是靜態變數,必須由static加以定義後才能成為靜態外部變數,或稱靜態全局變數。
對於自動變數,它屬於動態存儲方式。但是也可以用static定義它為靜態自動變數,或稱靜態局部變數,從而成為靜態存儲方式。由此看來,一個變數可由static進行再說明,並改變其原有的存儲方式。
而在以Pascal為代表的許多程序語言中,所有局部變數都由系統自動分配存儲空間,而所有全局變數的存儲空間則以靜態分配的方式獲取,因此由於實際上「局部變數」和「全局變數」這兩個術語已足以涵蓋所有的情況,在這些程序語言中通常不使用「靜態變數」這一術語,而直接以「全局變數」代之。
在這些程序語言中,靜態變數就是全局變數,而即使在有明確區分全局和靜態變數的程序語言中,在編譯後的代碼里二者也以相同的方式獲取存儲空間。而今術語「靜態變數」的概念則主要基於C族語言的「static」的定義。
靜態變數也可以用於存儲常數。具體來說,靜態變數可用const,constant或final等關鍵賣卜字標識,這時其值就會在編譯時設定,並且無法在運行時改變。編譯器通常將靜態常量與孝拿文本一起置於目標文件的文本區域,而非常量初始化數據則置於數據區
⑶ Java的核心技術有哪些
第一:Java虛擬機 Java虛擬機的主要任務是裝在class文件並且執行其中的位元組碼。Java虛擬機包含一個類裝載器,它可以從程序和API中裝載class文件。Java API中只有程序執行時需要的那些類才會被裝載。位元組碼由執行引擎來執行。不同的Java虛擬機中,執行引擎可能實現得非常不同。在由軟體實現的虛擬機中,最簡單的執行引擎就是一次性解釋位元組碼。另一種執行引擎更快,但是也更消耗內存,叫做"即時編譯器(just-in-time compiler)"。在這種情況下,第一次被執行的位元組碼會被編譯成本地機器代碼。編譯出的本地機器代碼會被緩存,當方法以後被調用的時候可以重用。第三種執行引擎是自適應優化器。在這種方法里,虛擬機開始的時候解釋位元組碼,但是會監視運行中程序的活動,並且記錄下使用最頻繁的代碼段。程序運行的時候,虛擬機只把那些活動最頻繁的代碼編譯成本地代碼,其他的代碼由於使用得不是很頻繁,繼續保留為位元組碼-由虛擬機繼續解釋它們。一個自適應的優化器可以使得Java虛擬機在80%~90%的時間里執行被優化過的本地代碼,而只需要編譯10%~20%的對性能有影響的代碼。 當Java虛擬機是由主機操作系統上的軟體實現的時候,Java程序通過調用本地方法(native method)和主機交互。Java中有兩種方法: Java方法和本地方法。Java方法是由Java語言編寫,編譯成位元組碼文件,存儲在class文件中的。本地方法是由其他語言(比如c,c++或匯編語言)編寫的,編譯成何處理器相關的機器代碼。本地方法保存在動態鏈接庫中,格式是各個平台專有的。運行中Java程序調用本地方法時,虛擬機裝載包含這個本地方法的動態庫,並調用這個方法。本地方法是聯系Java程序和底層主機操作系統的連接方法。
第二:類裝載器的體系結構 一個Java應用程序可以使用兩種類裝載器:"啟動(bootstrap)"類裝載器和用戶定義的類裝載器。啟動類裝載器(這是系統中唯一的)是Java虛擬機實現的一部分。啟動類裝載器通常使用某種默認方式從本地磁碟中裝載類,包括Java API類(啟動類裝載器也被稱為原始類裝載器、系統類裝載器或者默認類裝載器)。 Java應用程序能夠在運行時安裝用戶定義的類裝載器,這種類裝載器能夠使用自定義的方式來裝載類。例如,從網路下載class文件。盡管啟動類裝載器是虛擬機實現的本質部分,而用戶定義的類裝載器不是,但用戶定義的類裝載器能夠用Java來編寫,能夠被編譯成class文件,能夠被虛擬機裝載,還能夠像其它對象一樣實例化。 由於有用戶定義類裝載器,所以不必再編譯的時候就知道運行中的Java應用程序中最終會加入的所有的類。用戶定義的類裝載器使得在運行擴展Java應用程序成為可能。當它運行時,應用程序能夠解決它需要哪些額外的類,能夠決定是使用一個或是更多的用戶定義的類裝載器來裝載。由於類裝載器是用Java編寫的,所以用任何在Java代碼中可以表述的風格來進行類裝載。這些類可以通過網路下載,可以從某些資料庫中獲取,甚至可以動態生成。 每一個類被裝載的時候,Java虛擬機都監視這個類,看到它到底是被啟動類裝載器還是被用戶定義類裝載器裝載。當被裝載的類引用了另外一個類時,虛擬機就會使用裝載第一個類的類裝載器裝載引用的類。例如,如果虛擬機使用一個特定的類裝載器裝載Volcano這個類,它就會使用這個類裝載器裝載Volcano類使用的所有類。 由於Java虛擬機採取這種方式進行類的裝載,所以被裝載的類默認情況下只能看到被同一個類裝載器裝載的別的類。通過這種方法,Java的體系結構允許在一個Java應用程序中建立多個命名空間。運行時的Java程序中的每一個類裝載器都有自己的命名空間。 Java應用程序可以創建多少個(或多少種)被不同的類裝載器裝載的類存放在不同的命名空間中,它們不能相互訪問,除非應用程序顯示地允許這么做。當編寫一個Java應用程序的時候,從不同源文件裝載的類可以分隔在不同的命名空間中。通過這種方法,就能夠使用Java類裝載器的體系結構來控制任何不同源文件中裝載的代碼之間的相互影響,特別是能夠阻止惡意代碼獲取訪問或破壞善意代碼的許可權。 Web瀏覽器是一個動態擴展的例子,Web瀏覽器使用用戶定義的類裝載器從網路下載用於Java applet的class文件。Web瀏覽器使用一個用來安裝用戶定義類裝載器的Java應用程序。這個用戶定義的類裝載器通常被稱為Java Applet類裝載器,它知道如何向HTTP伺服器請求class文件。Java Applet可以作為動態擴展的例子,因為Java應用程序並不知道它什麼時候會開始從網路下載瀏覽器請求的class文件。只有當瀏覽器遇到有Java applet的頁面時,才決定是否需要下載class文件。 Web瀏覽器啟動的Java應用程序通常為每個提供class文件的網路地址分別創建不同的用戶定義類裝載器,因此,不同的用戶定義類裝載器裝載不同來源的class文件。這就可以把它們分別放置在Java主機應用程序的不同命名空間之下。由於不同來源的Java applet文件放置在不同的命名空間中,惡意的Java applet代碼就不會直接訪問從別的地方下載的class文件。這就能夠限制或阻止不同來源的代碼之間的相互訪問。
第三:Java class文件 Java class文件主要在平台無關性和網路移動性方面使Java更適合網路。它在平台無關性方面的任務是:為Java程序提供獨立於底層主機平台的二進制形式的服務。這種途徑途徑打破了C或者C++等語言所遵循的傳統,使用這些傳統語言寫的程序通常首先被編譯,然後被連接成單獨的、專門支持特定硬體平台和操作系統的二進制文件。通常情況下,一個平台上的二進制可執行文件不能在其他平台上工作。而Java class文件時可以運行在任何支持Java虛擬機的硬體平台和操作系統上的二進制文件。 當編譯和連接一個C++程序時,所獲得的可執行二進制文件只能在指定的硬體平台和操作系統上運行,因為這個二進制文件包含了對目標處理器的機器語言。而Java編譯器把Java源文件的指令翻譯成位元組碼,這種位元組碼就是Java虛擬機的"機器語言"。class文件設計得緊湊,因此它們可以快速地在網路上傳送。其次,由於Java程序是動態連接和動態擴展的,class文件可以在需要的時候才下載。這個特點使得Java應用程序能夠安排從網路上下載class文件的時間,從而可以最大限度地減少終端用戶的等待時間。
第四:Java API Java API通過支持平台無關性和安全性,使得Java適應於網路應用。Java API是運行庫的集合,它提供了一套訪問主機系統資源的標准方法。運行Java程序時,虛擬機裝載程序的class文件所使用的Java API class文件。所有被裝載的class文件(包括從應用程序中和從Java API中提取的)和所有已經裝載的動態庫(包含本地方法)共同組成了再Java虛擬機上運行的整個程序。 在一個平台能偶支持Java程序以前,必須在這個特定平台上明確地實現API的功能。為訪問主機上的本地資源,Java API調用了本地方法。由於Java API class文件調用了本地方法,Java程序就不需要再調用它們了。通過這種方法,Java API class文件為底層主機提供了具有平台無關性、標准介面的Java程序。對Java程序而言,無論平台內部如何,Java API都會有同樣的表現和可預測的行為。正是由於在每個特定的主機平台上明確地實現了Java虛擬機和Java API,因此,Java程序自身就能夠成為具有平台無關性的程序。 Java API在Java安全性模型方面也有貢獻。當Java API的方法進行任何有潛在危險的操作(比如進行本地磁碟寫操作)之前,都會通過查詢訪問控制器來檢驗是否得到了授權。訪問控制器是一個類,該類用來執行棧檢驗,已決定是否允許某種操作。
⑷ 什麼叫源文件
在開發軟體的過程中,我們需要將編寫好的代碼(Code)保存到一個文件中,這樣代碼才不會丟失,才能夠被編譯器找到,才能最終變成可執行文件。這種用來保存代碼的文件就叫做源文件(Source File)。
我們將在《編譯和鏈接》一節中講解編譯器的概念。
每種編程語言的源文件都有特定的後綴,以方便被編譯器識別,被程序員理解。源文件後綴大都根據編程語言本身的名字來命名,例如:
C語言源文件的後綴是.c;
C++語言(C Plus Plus)源文件的後綴是.cpp;
Java 源文件的後綴是.java;
Python 源文件的後綴是.py;
JavaScript 源文件後置是.js。
源文件其實就是純文本文件,它的內部並沒有特殊格式,能證明這一結論的典型例子是:在 Windows 下用記事本程序新建一個文本文檔,並命名為demo.txt,輸入一段C語言代碼並保存,然後將該文件強制重命名為demo.c(後綴從.txt變成了.c),發現編譯器依然能夠正確識別其中的C語言代碼,並順利生成可執行文件。
源文件的後綴僅僅是為了表明該文件中保存的是某種語言的代碼(例如.c文件中保存的是C語言代碼),這樣程序員更加容易區分,編譯器也更加容易識別,它並不會導致該文件的內部格式發生改變。
C++ 是站在C語言的肩膀上發展起來的,是在C語言的基礎上進行的擴展,C++ 包含了C語言的全部內容(請猛擊《C語言和C++到底有什麼關系》一文了解更多),將C語言代碼放在.cpp文件中不會有錯,很多初學者都是這么做的,很多大學老師也是這么教的。但是,我還是強烈建議將C語言代碼放在.c文件中,這樣能夠更加嚴格地遵循C語言的語法,也能夠更加清晰地了解C語言和C++的區別
⑸ C++編譯器即時編譯問題。
斷點中斷後所在的行是尚未運行准備運行的行,你可以按F10單步運行過去之後,就看到結果了。
if(ia[x++]<ia[x])
這句中由於 ++ 在後,所以判斷運算先進行,然後再增一,這種前後書寫有關系只有在多重運算下才會生效,單獨的 x++ 和 ++x 沒有區別。
⑹ Python編譯器推薦
1、CPython
是Python語言規范的參考實現,能夠優先獲得Python語言的最新、最強的功能,CPython是由C語言編寫而成,不但可以從Python代碼中調用C代碼的函數,還可以直接在Python中使用大量現有的C代碼庫。
2、Brython
Brython可用於在瀏覽器中運行包含了Python 3腳本的Web應用。
3、PyPy Python
雖然第一個推薦的是在Python中使用最廣泛的編譯器,但卻不是最快的,PyPy採用的是即時的編譯概念,在代碼執行前,就直接編譯為機器代碼,因此其執行速度提高了近4倍。
4、Jython或JPython
使用率第二高,Jython最初被稱為JPython,是通過Python語言來實現Java虛擬機的,開發者既可以將現有的Java包和代碼庫,導入自己的Python程序中,還可以在Java程序中嵌入Python腳本。
5、Cython
Cython與CPython不同,更像是一個超集,允許開發者在代碼中結合C和Python,從而生成C語言代碼類型的輸出,以供任何一種C/C++編譯器進行後續編譯。
6、Skulpt
流行的速度非常快,主要目的是提供一種良好的在線式Python編譯器,也可以通過讓Web應用引擎包含Skulpt,以方便開發者編寫出被用於前端的Python腳本。
7、PyJS
是另一款完全用Python去開發Web應用的編譯工具,在後台,PyJS會在使用內置的Ajax框架之前,將Python代碼編譯為JavaScript。
8、WinPython
是Python的"即用型"發行版,也就意味著用戶無需安裝,即可在Windows
PC上運行,作為另一種Python的實現,WinPython編譯器不僅帶來了Python執行環境,而且還包含了諸如:Scipy、Numpy、以及Pandas等各種Python庫。
⑺ C#JIT的概念及作用
C#編寫的程序,經過編譯器把編譯後,源代碼被轉換成Microsoft中間語言(MSIL)。MSIL不是真正可執行的代碼。因此,要真正執行MSIL應用程序,還必須使用「JIT編譯器」,對MSIL再次編譯,以得到主機處理器可以真正執行本機指令。JIT編譯器以即時方式編譯MSMIL代碼,以便應用程序執行。
⑻ c#泛型有什麼作用
關於object類型:
1.object類型可以來引用任何類型的實例;
2.object類型可以存儲任何類型的值;
3.可以定義object類型的參數;
4.可以把object作為返回類型。
但是--這樣做有很大的問題
1.會因為程序員沒有記住使用的類型而出錯,造成類型不兼容;
2.值類型和引用類型的互化即裝箱拆箱使系統性能下降。
C#2.0提出的泛型就是避免強制類型轉換,減少裝箱拆箱提高性能,減少錯誤。
System.Collections.Generic命名空間提供許多集合類和介面的泛型版本。
所謂泛型:
即通過參數化類型來實現在同一份代碼上操作多種數據類型。泛型編程是一種編程範式,它利用「參數化類型」將類型抽象化,從而實現更為靈活的復用。
C#泛型賦予了代碼更強的類型安全,更好的復用,更高的效率,更清晰的約束。
C#泛型能力由CLR在運行時支持,區別於C++的編譯時模板機制,和java的編譯時的「搽拭法」。這使得泛型能力可以在各個支持CLR的語言之間進行無縫的互操作。
C#泛型代碼在被編譯為IL和元數據時,採用特殊的佔位符來表示泛型類型,並用專有的IL指令支持泛型操作。而真正的泛型實例化工作以「on-demand」的方式,發生在JIT編譯時。
C#泛型編譯機制如下:
第一輪編譯時,編譯器只為Stack類型產生「泛型版」的IL代碼和元數據,並不進行泛型類型的實例化,T在中間只充當佔位符。
JIT編譯時,當JIT編譯器第一次遇到Stack時,將用int類型替換「泛型版」IL代碼與元數據中的T -- 進行泛型類型的實例化。
CLR為所有類型參數為「引用類型」的泛型類型產生同一份代碼,但如果類型參數為「值類型」,對每一個不同的「值類型」,CLR將為其產生一份獨立的代碼。
C#泛型的幾個特點
如果實例化泛型類型的參數相同,那麼JIT編譯器會重復使用該類型,因此C#的動態泛型能力避免了C++靜態模板可能導致的代碼膨脹的問題。
C#泛型類型攜帶有豐富的元數據,因此C#的泛型類型可以應用於強大的反射技術。
C#的泛型採用「基類、介面、構造器、值類型/引用類型」的約束方式來實現對類型參數的「顯示約束」,提高了類型安全的同時,也喪失了C++模板基於「簽名」的隱式約束所具有的高靈活性。
C#泛型類在編譯時,先生成中間代碼IL,通用類型T只是一個佔位符。在實例化類時,根據用戶指定的數據類型代替T並由即時編譯器(JIT)生成本地代碼,這個本地代碼中已經使用了實際的數據類型,等同於用實際類型寫的類,所以不同的封閉類的本地代碼是不一樣的。按照這個原理,我們可以這樣認為:泛型類的不同的封閉類是分別不同的數據類型。
這樣泛型不僅更加靈活,也同時將代碼的簡便和提高到一個層次!不用再為具體不同的重載方法寫具體的代碼了!
C# 泛型是開發工具庫中的一個無價之寶。它們可以提高性能、類型安全和質量,減少重復性的編程任務,簡化總體編程模型,而這一切都是通過優雅的、可讀性強的語法完成的。盡管 C# 泛型的根基是 C++ 模板,但 C# 通過提供編譯時安全和支持將泛型提高到了一個新水平。C# 利用了兩階段編譯、元數據以及諸如約束和一般方法之類的創新性的概念。毫無疑問,C# 的將來版本將繼續發展泛型,以便添加新的功能,並且將泛型擴展到諸如數據訪問或本地化之類的其他 .NET Framework 領域。
當然,C#的泛型還很多應用,現在我還只是了解了它的機制和原理,在接下來的學習中我會系統得學習泛型所支持的抽象泛型,介面泛型,結構和委託等!
具體的建議你看一下《deep in C#》這本書,上面解釋的很生動,很有趣。中文翻譯版的叫《深入理解C#》(第二版)。
⑼ linux中gnu的含義是什麼
1.3.2 GNU知識
GNU的全稱為GNU's not unix,意思是「GNU不是UNIX」,GNU計劃,又稱革奴計劃,是由Richard Stallman在1984年公開發起的,是FSF的主要項目。前面已經提到過,這個項目的目標是建立一套完全自由的和可移植的類Unix操作系統。
GNU類Unix操作系統是由一系列應用程序、系統庫和開發工具構成的軟體集合,例如:Emacs 編輯軟體、gcc 編譯軟體、bash 命令解釋程序和編程語言,以及gawk (GNU』s awk) 等,並加上了用於資源分配和硬體管理的內核。
但是GNU自己的內核Hurd仍在開發中,離實用還有一定的距離。因此,這個GNU系統並沒有流行起來。現在的GNU系統通常是使用Linux系統的內核、加上GNU項目貢獻的一些組件,以及其他相關程序組成的,這樣的組合被稱為GNU/Linux操作系統。
到1991年Linux內核發布的時候,GNU項目已經完成了除系統內核之外的各種必備軟體的開發。在Linus Torvalds和其他開發人員的努力下, GNU項目的部分組件又運行到了Linux內核之上,例如:GNU項目里的Emacs、gcc、bash、gawk等,至今都是Linux系統中很重要的基礎軟體。內容來自老男孩作者出版書籍。
⑽ 電腦編程的基礎知識——編譯器和連接器
我從沒見過(不過應該有)任何一本C++教材有講過何謂編譯器(Compiler)及連接器(Linker)(倒是在很老的C教材中見過),現在都通過一個類似VC這樣的編程環境隱藏了大量東西,將這些封裝起來。在此,對它們的理解是非常重要的,本系列後面將大量運用到這兩個詞彙,其決定了能否理解如聲明、定義、外部變數、頭文件等非常重要的關鍵。
前面已經說明了電腦編程就是一個「翻譯」過程,要把用戶的程序翻譯成CPU指令,其實也就是機器代碼。所謂的機器代碼就是用CPU指令書寫的程序,被稱作低級語言。而程序員的工作就是編寫出機器代碼。由於機器代碼完全是一些數字組成(CPU感知的一切都是數字,即使是指令,也只是1代表加法、2代表減法這一類的數字和工作的映射),人要記住1是代表加法、2是代表減法將比較困難,並且還要記住第3塊內存中放的是圓周率,而第4塊內存中放的是有效位數。所以發明了匯編語言,用一些符號表示加法而不再用1了,如用ADD表示加法等。
由於使用了匯編語言,人更容易記住了,但是電腦無法理解(其只知道1是加頌隱法,不知道ADD是加法,因為電腦只能看見數字),所以必須有個東西將匯編代碼翻譯成機器代碼,也就是所謂的編譯器。即編譯器是將一種語言翻譯成另一種語言的程序。即使使用了匯編語言,但由於其幾乎只是將CPU指令中的數字映射成符號以幫助記憶而已,還是使用的空跡電腦的思考方式進行思考的,不夠接近人類的思考習慣,故而出現了紛繁復雜的各種電腦編程語言,如:PASCAL、BASIC、C等,其被稱作高級語言,因為比較接近人的思考模式(尤其C++的類的概念的推出),而匯編語言則被稱作低級語言(C曾被稱作高級的低級語言),因為它們不是很符合人類的思考模式,人類書野虧廳寫起來比較困難。由於CPU同樣不認識這些PASCAL、BASIC等語言定義的符號,所以也同樣必須有一個編譯器把這些語言編寫的代碼轉成機器代碼。對於這里將要講到的C++語言,則是C++語言編譯器(以後的編譯器均指C++語言編譯器)。
因此,這里所謂的編譯器就是將我們書寫的C++源代碼轉換成機器代碼。由於編譯器執行一個轉換過程,所以其可以對我們編寫的代碼進行一些優化,也就是說其相當於是一個CPU指令程序員,將我們提供的程序翻譯成機器代碼,不過它的工作要簡單一些了,因為從人類的思考方式轉成電腦的思考方式這一過程已經由程序員完成了,而編譯器只是進行翻譯罷了(最多進行一些優化)。
還有一種編譯器被稱作翻譯器(Translator),其和編譯器的區別就是其是動態的而編譯器是靜態的。如前面的BASIC的編譯器在早期版本就被稱為翻譯器,因為其是在運行時期即時進行翻譯工作的,而不像編譯器一次性將所有代碼翻成機器代碼。對於這里的「動態」、「靜態」和「運行時期」等名詞,不用刻意去理解它,隨著後續文章的閱讀就會了解了。
編譯器把編譯後(即翻譯好的)的代碼以一定格式(對於VC,就是COFF通用對象文件格式,擴展名為.obj)存放在文件中,然後再由連接器將編譯好的機器代碼按一定格式在Windows操作系統下就是Portable Executable File Format--PE文件格式)存儲在文件中,以便以後操作系統執行程序時能按照那個格式找到應該執行的第一條指令或其他東西,如資源等。至於為什麼中間還要加一個連接器以及其它細節,在後續文章中將會進一步說明。