這是一些在工作中常用到的一些小技術(shù),拿出來和大家分享
1.用:set list來查看所有不可見字符,反之用:set nolist關(guān)閉
2.vim操作ftp,打開:
:e
ftp://192.168.0.1/1.txt
保存(如果不存在則創(chuàng)建):
:w
ftp://192.168.0.1/1.txt
讀取:
:r
ftp://192.168.0.1/1.txt
以上操作第一次打開時(shí)需要輸入用戶名和密碼,
以后就不用了,vim 會(huì)記住的。
3.Ctrl+R 是在編輯時(shí)或者命令行界面下調(diào)入寄存器值的熱鍵,Ctrl+R+/ 會(huì)得到上一次查詢的條件,Ctrl+R+<寄存器名>; 相當(dāng)于 Normal 模式下的 "<寄存器名>;p 命令
4.vim在編輯一個(gè)文件時(shí)如果打開多個(gè)文件,:args <CTRL-R>;% file2 file3
5.如何刪除連續(xù)兩行之間的回車符,使連續(xù)的兩行成為一行,Jx
6.想顯示行號(hào),可以用 :set nu
7.vim中光標(biāo)在C函數(shù)和系統(tǒng)調(diào)用上時(shí),按K進(jìn)入man手冊(cè)頁
8.V
打開"可視模式"(不是虛擬模式,虛擬是 virtual)后,可以有很多種辦法移動(dòng)光標(biāo)的,不一定非得用 h j k l , 比如可以搜索定位,
也可以用 [[ ]] ][ [] } { 等段落定位的命令. v]] v[[ v} 這樣就可以選中一大塊,而不用一行一行地選 還有 H L
這些都可以用. 詳細(xì)請(qǐng) help motion 另外, vim 內(nèi)置了很多以 a 打頭的文本對(duì)象, 如 a{ 表示一個(gè) {} 塊, ap
表示一個(gè)段落等等。=a{ 就可以重排當(dāng)前語法塊.
9.全選的命令是 ggVG gg表示到第一行第一個(gè)字母, V進(jìn)入visual line G則到文件尾。
10.vim是否支持將語法高亮度顯示的結(jié)果保存為一個(gè)html文檔,:TOhtml
11.用:split new | r!ls 來獲得外部命令的輸入,其中r !ls 則表示執(zhí)行外部命令 ls,并且捕獲(讀入)它的輸出。
12.vi中用``就可以回到剛才的位置,vim中用ctrl+o
13.用:set ai的命令來啟動(dòng)自動(dòng)縮進(jìn)。用:syntax on命令來啟動(dòng)語法著色
14.在"插入模式"下刪除光標(biāo)到行尾的字符,^od$,^o 表示同時(shí)按住 Ctrl 和 O 鍵,其實(shí)也可以是^oD,還有就是如果要?jiǎng)h除到某個(gè)字符位置的話,就用^odfx,x表示要?jiǎng)h除到的字符
15.自動(dòng)縮進(jìn)set autoindent 和set cindent
16.括號(hào)自動(dòng)補(bǔ)全:iab ( ()
17.刪除所有偶數(shù)行<ESC>;ggqajddq10000@a
18.排版代碼gg=G
19.:args查看正在編輯的文件名或者用ctrl+g
20.gj gk 分別可以向下、向上移動(dòng)一個(gè)物理行
這部分簡要介紹一下TCP/IP的內(nèi)部結(jié)構(gòu),為討論與互聯(lián)網(wǎng)有關(guān)的安全問題打下基礎(chǔ)。TCP/IP協(xié)議組之所以流行,部分原因是因?yàn)樗梢杂迷诟?
種各樣的信道和底層協(xié)議(例如T1和X.25、以太網(wǎng)以及RS-232串行接口)之上。確切地說,TCP/IP協(xié)議是一組包括TCP協(xié)議和IP協(xié)議,
UDP(User Datagram Protocol)協(xié)議、ICMP(Internet Control Message
Protocol)協(xié)議和其他一些協(xié)議的協(xié)議組。
TCP/IP協(xié)議的開發(fā)研制人員將Internet分為五個(gè)層次,以便于理解,它也稱為互聯(lián)網(wǎng)分層模型或互聯(lián)網(wǎng)分層參考模型,如下表:
應(yīng)用層(第五層)
傳輸層(第四層)
互聯(lián)網(wǎng)層(第三層)
網(wǎng)絡(luò)接口層(第二層)
物理層(第一層)
物理層:對(duì)應(yīng)于網(wǎng)絡(luò)的基本硬件,這也是Internet物理構(gòu)成,即我們可以看得見的硬設(shè)備,如PC機(jī)、互連網(wǎng)服務(wù)器、網(wǎng)絡(luò)設(shè)備等,必須對(duì)這些硬設(shè)備的電氣特性作一個(gè)規(guī)范,使這些設(shè)備都能夠互相連接并兼容使用。
網(wǎng)絡(luò)接口層:它定義了將資料組成正確幀的規(guī)程和在網(wǎng)絡(luò)中傳輸幀的規(guī)程,幀是指一串資料,它是資料在網(wǎng)絡(luò)中傳輸?shù)膯挝弧?
互聯(lián)網(wǎng)層:本層定義了互聯(lián)網(wǎng)中傳輸?shù)?#8220;信息包”格式,以及從一個(gè)用戶通過一個(gè)或多個(gè)路由器到最終目標(biāo)的"信息包"轉(zhuǎn)發(fā)機(jī)制。
傳輸層:為兩個(gè)用戶進(jìn)程之間建立、管理和拆除可靠而又有效的端到端連接。
應(yīng)用層:它定義了應(yīng)用程序使用互聯(lián)網(wǎng)的規(guī)程。
詳細(xì)請(qǐng)看
參考資料:
http://baike.baidu.com/view/7649.htm
By:dcboy / Comment:0 / Views: 5199
任務(wù)調(diào)度的crond常駐命令
crond 是linux用來定期執(zhí)行程序的命令。當(dāng)安裝完成操作系統(tǒng)之后,默認(rèn)便會(huì)啟動(dòng)此任務(wù)調(diào)度命令。crond命令每分鍾會(huì)定期檢查是否有要執(zhí)行的工作,如果有要執(zhí)行的工作便會(huì)自動(dòng)執(zhí)行該工作。而linux任務(wù)調(diào)度的工作主要分為以下兩類:
1、系統(tǒng)執(zhí)行的工作:系統(tǒng)周期性所要執(zhí)行的工作,如備份系統(tǒng)數(shù)據(jù)、清理緩存
2、個(gè)人執(zhí)行的工作:某個(gè)用戶定期要做的工作,例如每隔10分鐘檢查郵件服務(wù)器是否有新信,這些工作可由每個(gè)用戶自行設(shè)置
Crontab是UNIX系統(tǒng)下的定時(shí)任務(wù)觸發(fā)器,其使用者的權(quán)限記載在下列兩個(gè)文件中:
文件
|
含義
|
/etc/cron.deny
|
該文件中所列的用戶不允許使用Crontab命令
|
/etc/cron.allow
|
該文件中所列的用戶允許使用Crontab命令
|
/var/spool/cron/
|
是所有用戶的crontab文件
|
/var/spool/cron/crontabs
|
/var/spool/cron/crontabs
|
Crontab命令的格式為:crontab –l|-r|-e|-i [username],其參數(shù)含義如表一:
參數(shù)名稱
|
含義
|
示例
|
-l
|
顯示用戶的Crontab文件的內(nèi)容
|
crontabl –l
|
-i
|
刪除用戶的Crontab文件前給提示
|
crontabl -ri
|
-r
|
從Crontab目錄中刪除用戶的Crontab文件
|
crontabl -r
|
-e
|
編輯用戶的Crontab文件
|
crontabl -e
|
用戶所建立的Crontab文件存于/var/spool/cron中,其文件名與用戶名一致。
它的格式共分為六段,前五段為時(shí)間設(shè)定段,第六段為所要執(zhí)行的命令段,
格式如下:* * * * * <command>
其時(shí)間段的含義如表二:
段
|
含義
|
取值范圍
|
第一段
|
代表分鐘
|
0—59
|
第二段
|
代表小時(shí)
|
0—23
|
第三段
|
代表日期
|
1—31
|
第四段
|
代表月份
|
1—12
|
第五段
|
代表星期幾,0代表星期日
|
0—6
|
例:如果用戶的Crontab文件的內(nèi)容是:29 19 * * * echo its dinner time,則系統(tǒng)每天的19:29顯示‘its dinner time’
示例(創(chuàng)建一個(gè)cron全過程,每分鐘都會(huì)在test.txt里輸入當(dāng)前時(shí)間):
1. 以普通用戶登錄linux系統(tǒng)(我用的是CentOS4.1)
2. $crontab –e
說明:系統(tǒng)默認(rèn)的編輯器是VIM,如果不是請(qǐng)加上以下shell:
$EDITOR=vi
$export EDITOR
3. 輸入”*/1 * * * * date >> $HOME/test.txt”,save and exit VIM
4. $su root
5. $cd /etc/init.d
6. ./crond restart
下面看看看幾個(gè)具體的例子:
● 0 */2 * * * /sbin/service httpd restart 意思是每兩個(gè)小時(shí)重啟一次apache
● 50 7 * * * /sbin/service sshd start 意思是每天7:50開啟ssh服務(wù)
● 50 22 * * * /sbin/service sshd stop 意思是每天22:50關(guān)閉ssh服務(wù)
● 0 0 1,15 * * fsck /home 每月1號(hào)和15號(hào)檢查/home 磁盤
● 1 * * * * /home/bruce/backup 每小時(shí)的第一分執(zhí)行 /home/bruce/backup這個(gè)文件
● 00 03 * * 1-5 find /home "*.xxx" -mtime +4 -exec rm {} \; 每周一至周五3點(diǎn)鐘,在目錄/home中,查找文件名為*.xxx的文件,并刪除4天前的文件。
● 30 6 */10 * * ls 意思是每月的1、11、21、31日是的6:30執(zhí)行一次ls命令
命令如下:
$RESIN_HOME/bin/httpd.sh -conf $RESIN_HOME/conf/resin.conf -Djava.awt.headless=true -server 'servername' -pid 'log/coinstat.pid' -verbose start
1.命令行參數(shù)(Command-line arguments)
-install (Windows) install Resin as a service (but doesn't automatically start.)
-install-as xxx (Windows) install Resin as a named service (but doesn't utomatically start.)
-remove (Windows) install Resin as a service (but doesn't automatically start.)
-remove-as xxx (Windows) remove Resin as a named service (but doesn't automatically start.)
2.JDK參數(shù)(JDK arguments:在Httpd.sh參數(shù)的配置)
<1>.文件位置:${resin30}/bin/httpd.sh
<2>.a(chǎn)rgs='-J-server -Xms200m -Xmx1024m -Xloggc:./log/gc.log -XX:MaxNewSize=256m -XX:MaxPermSize=256m -Djava.awt.headless=true'
參數(shù)說明:
(1)J-server -Xms200m -Xmx1024m 其中,-Xms200m 表示啟動(dòng)時(shí),初時(shí)內(nèi)存大小,-Xmx1024m最大內(nèi)存占用大小。(-Xmn100m可選)
(2)-XX:MaxNewSize=256m -XX:MaxPermSize=256m 表示:內(nèi)存的永久保存區(qū)域(PermGen space)的大小,PermGen space的全稱是Permanent Generation space,是指內(nèi)存的永久保存區(qū)域OutOfMemoryError: PermGen space從表面上看就是內(nèi)存溢出,解決方法也一定是加大內(nèi)存。說說為什么會(huì)內(nèi)存益出:這一部分用于存放Class和Meta的信息,Class在被 Load的時(shí)候被放入PermGen space區(qū)域,它和和存放Instance的Heap區(qū)域不同,GC(Garbage Collection)不會(huì)在主程序運(yùn)行期對(duì)PermGen space進(jìn)行清理
一般 -XX:PermSize=64M -XX:MaxNewSize=256m -XX:MaxPermSize=128m這些值不需要設(shè)置的,除非perm溢出,設(shè)置一下MaxPermSize就行,啟動(dòng)腳本加上-server后,也不用在設(shè)置MaxNewSize。
(3)-Djava.awt.headless=true 解決在linux/unix驗(yàn)證碼圖片不能顯示的問題。
3.通用 JVM 參數(shù)
指定傳遞到啟動(dòng)應(yīng)用程序服務(wù)器進(jìn)程的 Java 虛擬機(jī)代碼的命令行參數(shù)。
下面是可以在“通用 JVM 參數(shù)”字段中輸入的可選命令行參數(shù)。如果輸入多個(gè)自變量,請(qǐng)?jiān)诿總€(gè)自變量之間輸入空格。
重要: 如果該參數(shù)表明它僅適用于 IBM Developer Kit,您就無法為另一個(gè) JVM 使用該參數(shù),例如 Sun JDK 或 HP JDK。
-Xquickstart
可以使用 -Xquickstart 來以低于缺省方式的優(yōu)化級(jí)別進(jìn)行初始編譯。之后,根據(jù)采樣結(jié)果的不同,可以采用缺省方式下初始編譯的級(jí)別來進(jìn)行重新編譯。適合于早期的平均速度比長期運(yùn)行吞吐量更為重要的應(yīng)用程序 -Xquickstart。在某些調(diào)試方案、測(cè)試裝置和短時(shí)間運(yùn)行的工具中,可以將啟動(dòng)時(shí)間縮短 15% 到 20%。
-Xverify:none
如果在類裝入期間要跳過類驗(yàn)證階段,可以使用 -Xverify:none。在啟用即時(shí)(JIT)編譯器的情況下使用 -Xverify:none 能夠?qū)?dòng)時(shí)間縮短 10-15%。
-Xnoclassgc
可以使用 -Xnoclassgc 來禁用類垃圾回收。此操作可以提高類重用程度,并可以略微提高性能。但是,其代價(jià)是您無法收集這些類擁有的資源。可以使用 verbose:gc 配置設(shè)置(此設(shè)置將輸出類垃圾回收統(tǒng)計(jì)信息)來監(jiān)控垃圾回收。檢查這些統(tǒng)計(jì)信息將幫助您理解再生的資源和再生資源必需的垃圾回收量之間的平衡。然而,如果在您的工作負(fù)載中反復(fù)地垃圾回收同一組類,那么您應(yīng)該禁用垃圾回收。缺省情況下,啟用類垃圾回收。
-Xgcthreads
可以同時(shí)使用數(shù)個(gè)垃圾回收線程,這也稱為并行垃圾回收。在“通用 JVM 參數(shù)”字段中輸入此值時(shí),還要輸入您的機(jī)器的處理器數(shù),例如,-Xgcthreadsn,其中 n 是處理器數(shù)。在具有 n 個(gè)處理器的節(jié)點(diǎn)上,缺省線程數(shù)是 n。如果您的機(jī)器有多個(gè)處理器,那么您應(yīng)該使用并行垃圾回收。此參數(shù)僅對(duì)于 IBM Developer Kit 是有效的。
-Xnocompactgc
可以使用 -Xnocompactgc 來禁用堆壓縮,這是成本最高的垃圾回收操作。在 IBM Developer Kit 中避免壓縮。如果您禁用堆壓縮,那么消除了所有相關(guān)的開銷。
-Xinitsh
可以使用 -Xinitsh 來設(shè)置存儲(chǔ)類對(duì)象的堆的初始大小。方法定義和靜態(tài)字段也與類對(duì)象一起存儲(chǔ)。盡管系統(tǒng)堆大小沒有上限,但是設(shè)置初始大小,以避免產(chǎn)生涉及調(diào)用操作系統(tǒng)內(nèi)存管理器的擴(kuò)展系統(tǒng)堆大小的花銷。您可以通過了解 WebSphere Application Server 產(chǎn)品中裝入的類數(shù)目(大約是 8,000 個(gè)類)以及它們的平均大小,來計(jì)算理想的初始系統(tǒng)堆大小。了解應(yīng)用程序可幫助您將它們計(jì)算進(jìn)去。您只可以為 IBM Developer Kit 使用此參數(shù)。
-Xgpolicy
可以使用 -Xgpolicy 來設(shè)置垃圾回收策略。如果垃圾回收策略(gcpolicy)設(shè)置為 optavgpause,使用并發(fā)作標(biāo)記跟蹤在堆滿之前從堆棧啟動(dòng)的應(yīng)用程序線程。垃圾回收器暫停變得協(xié)調(diào)統(tǒng)一了,并且長時(shí)間的暫停也不再明顯了。其代價(jià)是吞吐量降低,這是因?yàn)榫€程可能必須要執(zhí)行額外的操作。缺省的建議值為 optthruput。輸入值 -Xgcpolicy:[optthruput|optavgpause]。您只可以為 IBM Developer Kit 使用此參數(shù)。
-XX
基于 Sun 的 Java Development Kit(JDK)V1.4.2 有生成垃圾回收功能,這允許分隔內(nèi)存池以包含不同時(shí)效的對(duì)象。垃圾回收循環(huán)根據(jù)時(shí)效收集與其他對(duì)象彼此獨(dú)立的對(duì)象。使用其他參數(shù),您可以單獨(dú)設(shè)置內(nèi)存池的大小。為了實(shí)現(xiàn)更好的性能,您應(yīng)該對(duì)包含短期存活對(duì)象的池的大小進(jìn)行設(shè)置,以使該池中的對(duì)象的存活時(shí)間不會(huì)超過一個(gè)垃圾回收循環(huán)。新生成的池的大小由 NewSize 和 MaxNewSiz 參數(shù)確定。
第一次垃圾回收循環(huán)中存活下來的對(duì)象轉(zhuǎn)移到另一個(gè)池中。生還者池的大小由參數(shù) SurvivorRatio 確定。如果垃圾回收變成了瓶頸,您可以嘗試定制生成池設(shè)置。要監(jiān)控垃圾回收統(tǒng)計(jì)信息,使用 Tivoli Performance Viewer 中的對(duì)象統(tǒng)計(jì)信息或 verbose:gc 配置設(shè)置。輸入下列值:
-XX:NewSize (lower bound)
-XX:MaxNewSize (upper bound)
-XX:SurvivorRatio=NewRatioSize
缺省值為:NewSize=2m MaxNewSize=32m SurvivorRatio=2。但是,如果 JVM 的堆大小大于 1GB,那么應(yīng)該使用值:-XX:newSize=640m -XX:MaxNewSize=640m -XX:SurvivorRatio=16,或者將堆的總大小的 50% 到 60% 分配給新生成的池。
-Xminf
可以使用 -Xminf 來指定最小可用堆大小百分比。如果可用空間低于指定量,那么堆增長。在啟用復(fù)位的方式中,此選項(xiàng)指定中間件和瞬態(tài)堆的可用空間的最小百分率。這是
-server | -client
基于 Sun 的 Java Development Kit(JDK)V1.4.2 中的 Java 熱點(diǎn)技術(shù)引入了一種自適應(yīng) JVM,該 JVM 包含用于隨著時(shí)間的推移而優(yōu)化字節(jié)碼執(zhí)行的算法。JVM 以兩種方式運(yùn)行,分別為 -server 和 -client。如果您使用缺省值 -client 方式,將會(huì)獲得較快的啟動(dòng)時(shí)間以及較小的內(nèi)存占用量,但是獲得的擴(kuò)展性能也較低。如果有足夠的時(shí)間來允許 HotSpot JVM 通過執(zhí)行連續(xù)執(zhí)行字節(jié)代碼來熱身,您可以使用 -server 方式以增強(qiáng)性能。在大多數(shù)情況下,應(yīng)該使用 -server 方式,這將長時(shí)間地保持運(yùn)行時(shí)執(zhí)行高效運(yùn)行。您可以監(jiān)控進(jìn)程大小以及服務(wù)器啟動(dòng)時(shí)間,來檢查 -client 和 -server 之間的區(qū)別。
用MyEclipse寫web工程時(shí),總是顯示jsp文件錯(cuò)誤,很不爽,我們可以不讓它進(jìn)行語法檢查:
右鍵你的工程-- MyEclipse --
Exclude From Validation即可以去掉語法檢查。
請(qǐng)到這里下載我的錄像:
http://download.csdn.net/source/457437
jetty-7.0.0pre1在MyEclipse 5.0M1中應(yīng)用配置
公司有一個(gè)項(xiàng)目需要使用一個(gè)嵌入式web server,在網(wǎng)上找了一通也沒找著一篇完整的文章,現(xiàn)整理一份出來,便與大家參考。
需特別注意的是Jetty 6.0以前的版本和后來的是有差別的,以下為jetty-7.0.0pre1在myEclipse 5.0M1中應(yīng)用配置步驟:
它的原理在網(wǎng)上很多,看源代碼也好,我這里只說明應(yīng)用
我的環(huán)境:
windows 2000 + JDK 1.5.0_08 + Eclipse 3.2.1 + MyEclipse 5.0M1
錄像從第2步開始
1、下載jetty-7.0.0pre1
我下的是最新版的,下載地址:ftp://ftp.mortbay.org/pub/
解壓到相應(yīng)的目錄,我解到了d:/
2、打開myEclipse,
a.新建java工程JettyTest
b.建立source folder src
c.建立目錄 conf, contexts, logs, webapps
d.在webapps建立manage目錄作為web工作目錄
e.在src下建包c(diǎn)om.willpower.jetty
f.將D:\jetty-7.0.0pre1\lib下的三個(gè)jar包加入工程的classpath, 將D:\jetty-7.0.0pre1\lib\jsp-2.1下的四個(gè)jar包加入工程的classpath
g.copy D:\jetty-7.0.0pre1\etc下的jetty.xml, webdefault.xml和realm.properties到conf下
h.copy D:\jetty-7.0.0pre1\contexts下的test.xml到contexts下并改名為manage.xml
i.修改jetty.xml, manage.xml
j.在webapps/manage下新建index.jsp
k.在src/com.willpower.jetty 里新建Start.java并加入main(),加入以下代碼:
Server server = new Server(8080);
server.setHandler(new DefaultHandler());
XmlConfiguration cfg = null;
try {
cfg = new XmlConfiguration(new FileInputStream("./conf/jetty.xml"));
cfg.configure(server);
server.start();
System.out.println("Jetty Started ...");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
l.運(yùn)行Start類,用IE訪問http://localhost:8080/, 點(diǎn)擊/manage ---> org.mortbay.jetty.webapp.WebAppContext@bb05de
剛才是因?yàn)橥浶薷膉etty.xml所致
到此Jetty運(yùn)行JSP成功
停止服務(wù)
3、繼續(xù)在Jetty中運(yùn)行servlet
a.在webapps/manage下建立WEB-INF, 并新建web.xml用于配置servlet, 并將contexts下的webdefalut.xml的內(nèi)容copy到web.xml里
修改contexts下的manage.xml
b.在src下新建包c(diǎn)om.willpower.servlet, 并新建servlet Manage
request.setCharacterEncoding("GB2312");
String name = request.getParameter("name");
System.out.println("您提交的數(shù)據(jù)為:" + name);
System.out.println("OK");
c.在web.xml里配置servlet, 將下面的代碼加入web.xml的servlet配置區(qū)域
<servlet>
<servlet-name>Manage</servlet-name>
<servlet-class>com.willpower.servlet.Manage</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Manage</servlet-name>
<url-pattern>/Manage</url-pattern>
</servlet-mapping>
d.修改webapps/manage/index.jsp,加入以下代碼
<br>
<form name="manage" method="Post" action="/manage/Manage">
<input type="text" name="name" />
<input type="submit" name="button2" value="提交" />
</form>
e.運(yùn)行Start類,用IE訪問http://localhost:8080/, 點(diǎn)擊/manage ---> org.mortbay.jetty.webapp.WebAppContext@bb05de
f.到此Jetty運(yùn)行servlet成功
停止服務(wù)
希望對(duì)大家有所幫助 2008-05-16 18:16
轉(zhuǎn)自
http://blog.csdn.net/shengbox/archive/2007/09/18/1789647.aspx
照編譯原理的觀點(diǎn),程序運(yùn)行時(shí)的內(nèi)存分配有三種策略,分別是靜態(tài)的,棧式的,和堆式的.
靜態(tài)存儲(chǔ)分配是指在編譯時(shí)就能確定
每個(gè)數(shù)據(jù)目標(biāo)在運(yùn)行時(shí)刻的存儲(chǔ)空間需求,因而在編譯時(shí)就可以給他們分配固定的內(nèi)存空間.這種分配策略要求程序代碼中不允許有可變數(shù)據(jù)結(jié)構(gòu)(比如可變數(shù)組)
的存在,也不允許有嵌套或者遞歸的結(jié)構(gòu)出現(xiàn),因?yàn)樗鼈兌紩?huì)導(dǎo)致編譯程序無法計(jì)算準(zhǔn)確的存儲(chǔ)空間需求.
棧式存儲(chǔ)分配也可稱為動(dòng)態(tài)存儲(chǔ)分配,是
由一個(gè)類似于堆棧的運(yùn)行棧來實(shí)現(xiàn)的.和靜態(tài)存儲(chǔ)分配相反,在棧式存儲(chǔ)方案中,程序?qū)?shù)據(jù)區(qū)的需求在編譯時(shí)是完全未知的,只有到運(yùn)行的時(shí)候才能夠知道,但是
規(guī)定在運(yùn)行中進(jìn)入一個(gè)程序模塊時(shí),必須知道該程序模塊所需的數(shù)據(jù)區(qū)大小才能夠?yàn)槠浞峙鋬?nèi)存.和我們?cè)跀?shù)據(jù)結(jié)構(gòu)所熟知的棧一樣,棧式存儲(chǔ)分配按照先進(jìn)后出的
原則進(jìn)行分配。
靜態(tài)存儲(chǔ)分配要求在編譯時(shí)能知道所有變量的存儲(chǔ)要求,棧式存儲(chǔ)分配要求在過程的入口處必須知道所有的存儲(chǔ)要求,而堆式存儲(chǔ)分
配則專門負(fù)責(zé)在編譯時(shí)或運(yùn)行時(shí)模塊入口處都無法確定存儲(chǔ)要求的數(shù)據(jù)結(jié)構(gòu)的內(nèi)存分配,比如可變長度串和對(duì)象實(shí)例.堆由大片的可利用塊或空閑塊組成,堆中的內(nèi)
存可以按照任意順序分配和釋放.
堆和棧的比較
上面的定義從編譯原理的教材中總結(jié)而來,除靜態(tài)存儲(chǔ)分配之外,都顯得很呆板和難以理解,下面撇開靜態(tài)存儲(chǔ)分配,集中比較堆和棧:
從堆和棧的功能和作用來通俗的比較,堆主要用來存放對(duì)象的,棧主要是用來執(zhí)行程序的.而這種不同又主要是由于堆和棧的特點(diǎn)決定的:
在編程中,例如C/C++中,所有的方法調(diào)用都是通過棧來進(jìn)行的,所有的局部變量,形式參數(shù)都是從棧中分配內(nèi)存空間的。實(shí)際上也不是什么分配,只是從棧頂
向上用就行,就好像工廠中的傳送帶(conveyor belt)一樣,Stack Pointer會(huì)自動(dòng)指引你到放東西的位置,你所要做的只是把東西放
下來就行.退出函數(shù)的時(shí)候,修改棧指針就可以把棧中的內(nèi)容銷毀.這樣的模式速度最快,當(dāng)然要用來運(yùn)行程序了.需要注意的是,在分配的時(shí)候,比如為一個(gè)即將
要調(diào)用的程序模塊分配數(shù)據(jù)區(qū)時(shí),應(yīng)事先知道這個(gè)數(shù)據(jù)區(qū)的大小,也就說是雖然分配是在程序運(yùn)行時(shí)進(jìn)行的,但是分配的大小多少是確定的,不變的,而這個(gè)"大小
多少"是在編譯時(shí)確定的,不是在運(yùn)行時(shí).
堆是應(yīng)用程序在運(yùn)行的時(shí)候請(qǐng)求操作系統(tǒng)分配給自己內(nèi)存,由于從操作系統(tǒng)管理的內(nèi)存分配,所以在分配
和銷毀時(shí)都要占用時(shí)間,因此用堆的效率非常低.但是堆的優(yōu)點(diǎn)在于,編譯器不必知道要從堆里分配多少存儲(chǔ)空間,也不必知道存儲(chǔ)的數(shù)據(jù)要在堆里停留多長的時(shí)
間,因此,用堆保存數(shù)據(jù)時(shí)會(huì)得到更大的靈活性。事實(shí)上,面向?qū)ο蟮亩鄳B(tài)性,堆內(nèi)存分配是必不可少的,因?yàn)槎鄳B(tài)變量所需的存儲(chǔ)空間只有在運(yùn)行時(shí)創(chuàng)建了對(duì)象之
后才能確定.在C++中,要求創(chuàng)建一個(gè)對(duì)象時(shí),只需用new命令編制相關(guān)的代碼即可。執(zhí)行這些代碼時(shí),會(huì)在堆里自動(dòng)進(jìn)行數(shù)據(jù)的保存.當(dāng)然,為達(dá)到這種靈活
性,必然會(huì)付出一定的代價(jià):在堆里分配存儲(chǔ)空間時(shí)會(huì)花掉更長的時(shí)間!這也正是導(dǎo)致我們剛才所說的效率低的原因,看來列寧同志說的好,人的優(yōu)點(diǎn)往往也是人的
缺點(diǎn),人的缺點(diǎn)往往也是人的優(yōu)點(diǎn)(暈~).
JVM中的堆和棧
JVM是基于堆棧的虛擬機(jī).JVM為每個(gè)新創(chuàng)建的線程都分配一個(gè)堆棧.也就是說,對(duì)于一個(gè)Java程序來說,它的運(yùn)行就是通過對(duì)堆棧的操作來完成的。堆棧以幀為單位保存線程的狀態(tài)。JVM對(duì)堆棧只進(jìn)行兩種操作:以幀為單位的壓棧和出棧操作。
我們知道,某個(gè)線程正在執(zhí)行的方法稱為此線程的當(dāng)前方法.我們可能不知道,當(dāng)前方法使用的幀稱為當(dāng)前幀。當(dāng)線程激活一個(gè)Java方法,JVM就會(huì)在線程的
Java堆棧里新壓入一個(gè)幀。這個(gè)幀自然成為了當(dāng)前幀.在此方法執(zhí)行期間,這個(gè)幀將用來保存參數(shù),局部變量,中間計(jì)算過程和其他數(shù)據(jù).這個(gè)幀在這里和編譯
原理中的活動(dòng)紀(jì)錄的概念是差不多的.
從Java的這種分配機(jī)制來看,堆棧又可以這樣理解:堆棧(Stack)是操作系統(tǒng)在建立某個(gè)進(jìn)程時(shí)或者線程(在支持多線程的操作系統(tǒng)中是線程)為這個(gè)線程建立的存儲(chǔ)區(qū)域,該區(qū)域具有先進(jìn)后出的特性。
每一個(gè)Java應(yīng)用都唯一對(duì)應(yīng)一個(gè)JVM實(shí)例,每一個(gè)實(shí)例唯一對(duì)應(yīng)一個(gè)堆。應(yīng)用程序在運(yùn)行中所創(chuàng)建的所有類實(shí)例或數(shù)組都放在這個(gè)堆中,并由應(yīng)用所有的線程
共享.跟C/C++不同,Java中分配堆內(nèi)存是自動(dòng)初始化的。Java中所有對(duì)象的存儲(chǔ)空間都是在堆中分配的,但是這個(gè)對(duì)象的引用卻是在堆棧中分配,也
就是說在建立一個(gè)對(duì)象時(shí)從兩個(gè)地方都分配內(nèi)存,在堆中分配的內(nèi)存實(shí)際建立這個(gè)對(duì)象,而在堆棧中分配的內(nèi)存只是一個(gè)指向這個(gè)堆對(duì)象的指針(引用)而已。
GC的思考
Java為什么慢?JVM的存在當(dāng)然是一個(gè)原因,但有人說,在Java中,除了簡單類型(int,char等)的數(shù)據(jù)結(jié)構(gòu),其它都是在堆中分配內(nèi)存(所以說Java的一切都是對(duì)象),這也是程序慢的原因之一。
我的想法是(應(yīng)該說代表TIJ的觀點(diǎn)),如果沒有Garbage Collector(GC),上面的說法就是成立的.堆不象棧是連續(xù)的空間,沒有辦法指
望堆本身的內(nèi)存分配能夠象堆棧一樣擁有傳送帶般的速度,因?yàn)?誰會(huì)為你整理龐大的堆空間,讓你幾乎沒有延遲的從堆中獲取新的空間呢?
這個(gè)時(shí)
候,GC站出來解決問題.我們都知道GC用來清除內(nèi)存垃圾,為堆騰出空間供程序使用,但GC同時(shí)也擔(dān)負(fù)了另外一個(gè)重要的任務(wù),就是要讓Java中堆的內(nèi)存
分配和其他語言中堆棧的內(nèi)存分配一樣快,因?yàn)樗俣鹊膯栴}幾乎是眾口一詞的對(duì)Java的詬病.要達(dá)到這樣的目的,就必須使堆的分配也能夠做到象傳送帶一樣,
不用自己操心去找空閑空間.這樣,GC除了負(fù)責(zé)清除Garbage外,還要負(fù)責(zé)整理堆中的對(duì)象,把它們轉(zhuǎn)移到一個(gè)遠(yuǎn)離Garbage的純凈空間中無間隔的
排列起來,就象堆棧中一樣緊湊,這樣Heap Pointer就可以方便的指向傳送帶的起始位置,或者說一個(gè)未使用的空間,為下一個(gè)需要分配內(nèi)存的對(duì)象"
指引方向".因此可以這樣說,垃圾收集影響了對(duì)象的創(chuàng)建速度,聽起來很怪,對(duì)不對(duì)?
那GC怎樣在堆中找到所有存活的對(duì)象呢?前面說了,在建
立一個(gè)對(duì)象時(shí),在堆中分配實(shí)際建立這個(gè)對(duì)象的內(nèi)存,而在堆棧中分配一個(gè)指向這個(gè)堆對(duì)象的指針(引用),那么只要在堆棧(也有可能在靜態(tài)存儲(chǔ)區(qū))找到這個(gè)引
用,就可以跟蹤到所有存活的對(duì)象.找到之后,GC將它們從一個(gè)堆的塊中移到另外一個(gè)堆的塊中,并將它們一個(gè)挨一個(gè)的排列起來,就象我們上面說的那樣,模擬
出了一個(gè)棧的結(jié)構(gòu),但又不是先進(jìn)后出的分配,而是可以任意分配的,在速度可以保證的情況下,Isn't it great?
但是,列寧同志
說了,人的優(yōu)點(diǎn)往往也是人的缺點(diǎn),人的缺點(diǎn)往往也是人的優(yōu)點(diǎn)(再暈~~).GC()的運(yùn)行要占用一個(gè)線程,這本身就是一個(gè)降低程序運(yùn)行性能的缺陷,更何況
這個(gè)線程還要在堆中把內(nèi)存翻來覆去的折騰.不僅如此,如上面所說,堆中存活的對(duì)象被搬移了位置,那么所有對(duì)這些對(duì)象的引用都要重新賦值.這些開銷都會(huì)導(dǎo)致
性能的降低.
此消彼長,GC()的優(yōu)點(diǎn)帶來的效益是否蓋過了它的缺點(diǎn)導(dǎo)致的損失,我也沒有太多的體會(huì),Bruce Eckel 是Java的支持者,王婆賣瓜,話不能全信.個(gè)人總的感覺是,Java還是很慢,它的發(fā)展還需要時(shí)間.
上面的體會(huì)是我看了TIJ.3rdEdition.Revision4.0中第四章之后得出的,內(nèi)容和前面的有些不同.我沒有看過侯捷的中文版本,但我覺得,在關(guān)鍵問題上,原版的TIJ的確更值得一讀.所以和中文版配合起來學(xué)習(xí)是比較不錯(cuò)的選擇.
我只能算一個(gè)Java的初學(xué)者,沒想到起了這么個(gè)題目,卻受到這么多人的關(guān)注,欣喜之余,也決心盡力寫好下面的每一篇.不過這一篇完了,我就該準(zhǔn)備赴美簽
證了,如果成功,那就要等到8月27號(hào)CS的研究生院開學(xué)之后,才有時(shí)間會(huì)開始研究下一章了,希望可以多從原版中獲取一點(diǎn)經(jīng)驗(yàn).
Linux 包含了一個(gè)叫 gdb 的 GNU 調(diào)試程序. gdb 是一個(gè)用來調(diào)試 C 和 C++ 程序的強(qiáng)力調(diào)試器. 它使你能在程序運(yùn)行時(shí)觀察程序的內(nèi)部結(jié)構(gòu)和內(nèi)存的使用情況. 以下是 gdb 所提供的一些功能:
1、啟動(dòng)你的程序,可以按照你的自定義的要求隨心所欲的運(yùn)行程序。
2、可讓被調(diào)試的程序在你所指定的調(diào)置的斷點(diǎn)處停住。(斷點(diǎn)可以是條件表達(dá)式)
3、當(dāng)程序被停住時(shí),可以檢查此時(shí)你的程序中所發(fā)生的事。
4、動(dòng)態(tài)的改變你程序的執(zhí)行環(huán)境。
當(dāng)你啟動(dòng)
gdb 后, 你能在命令行上指定很多的選項(xiàng). 可以以下面的方式來運(yùn)行
gdb gdb <fname>
當(dāng)你用這種方式運(yùn)行
gdb , 你能直接指定想要調(diào)試的程序. 這將告訴
gdb 裝入名為 fname 的可執(zhí)行文件. 你也可以用
gdb 去檢查一個(gè)因程序異常終止而產(chǎn)生的 core 文件, 或者與一個(gè)正在運(yùn)行的程序相連. 你可以參考
gdb 指南頁或在命令行上鍵入
gdb -h 得到一個(gè)有關(guān)這些選項(xiàng)的說明的簡單列表.
為調(diào)試編譯代碼
為了使
gdb 正常工作, 你必須使你的程序在編譯時(shí)包含調(diào)試信息. 調(diào)試信息包含你程序里的每個(gè)變量的類型和在可執(zhí)行文件里的地址映射以及源代碼的行號(hào).
gdb 利用這些信息使源代碼和機(jī)器碼相關(guān)聯(lián).
在編譯時(shí)用 -g 選項(xiàng)打開調(diào)試選項(xiàng).
命 令 |
描 述 |
file |
裝入想要調(diào)試的可執(zhí)行文件. |
kill |
終止正在調(diào)試的程序. |
list |
列出產(chǎn)生執(zhí)行文件的源代碼的一部分. |
next |
執(zhí)行一行源代碼但不進(jìn)入函數(shù)內(nèi)部. |
step |
執(zhí)行一行源代碼而且進(jìn)入函數(shù)內(nèi)部. |
run |
執(zhí)行當(dāng)前被調(diào)試的程序 |
quit |
終止 gdb |
watch |
使你能監(jiān)視一個(gè)變量的值而不管它何時(shí)被改變. |
break |
在代碼里設(shè)置斷點(diǎn), 這將使程序執(zhí)行到這里時(shí)被掛起. |
make |
使你能不退出 gdb 就可以重新產(chǎn)生可執(zhí)行文件. |
shell |
使你能不離開 gdb 就執(zhí)行 UNIX shell 命令. |
(a)設(shè)置斷點(diǎn)
break 20;---在第20行設(shè)置斷點(diǎn)
break func;---在函數(shù)func的入口處設(shè)置斷點(diǎn)
(b)取消斷點(diǎn)
delete break 20;---取消第20行的斷點(diǎn)
delete break func;---取消函數(shù)func入口處的斷點(diǎn)
(c)運(yùn)行代碼
run;
r;
(d)顯示變量或函數(shù)值
display;
p;
(e)單步執(zhí)行
next;
n;
(f)跳步執(zhí)行
step;
s;
(g)循環(huán)執(zhí)行
continue;
c;
(h)列出運(yùn)行棧內(nèi)容
bt;
一個(gè)調(diào)試示例
——————
源程序:tst.c
1 #include <stdio.h>
2
3 int func(int n)
4 {
5 int sum=0,i;
6 for(i=0; i<n; i++)
7 {
8 sum+=i;
9 }
10 return sum;
11 }
12
13
14 main()
15 {
16 int i;
17 long result = 0;
18 for(i=1; i<=100; i++)
19 {
20 result += i;
21 }
22
23 printf("result[1-100] = %d \n", result );
24 printf("result[1-250] = %d \n", func(250) );
25 }
編譯生成執(zhí)行文件:(Linux下)
cc -g tst.c -o tst
使用GDB調(diào)試:
gdb tst <---------- 啟動(dòng)GDB
GNU gdb 5.1.1
Copyright 2002 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "i386-SuSE-linux"...
(gdb) l <-------------------- l命令相當(dāng)于list,從第一行開始例出原碼。
1 #include <stdio.h>
2
3 int func(int n)
4 {
5 int sum=0,i;
6 for(i=0; i<n; i++)
7 {
8 sum+=i;
9 }
10 return sum;
(gdb) <-------------------- 直接回車表示,重復(fù)上一次命令
11 }
12
13
14 main()
15 {
16 int i;
17 long result = 0;
18 for(i=1; i<=100; i++)
19 {
20 result += i;
(gdb) break 16 <-------------------- 設(shè)置斷點(diǎn),在源程序第16行處。
Breakpoint 1 at 0x8048496: file tst.c, line 16.
(gdb) break func <-------------------- 設(shè)置斷點(diǎn),在函數(shù)func()入口處。
Breakpoint 2 at 0x8048456: file tst.c, line 5.
(gdb) info break <-------------------- 查看斷點(diǎn)信息。
Num Type Disp Enb Address What
1 breakpoint keep y 0x08048496 in main at tst.c:16
2 breakpoint keep y 0x08048456 in func at tst.c:5
(gdb) r <--------------------- 運(yùn)行程序,run命令簡寫
Starting program: /home/hchen/test/tst
Breakpoint 1, main () at tst.c:17 <---------- 在斷點(diǎn)處停住。
17 long result = 0;
(gdb) n <--------------------- 單條語句執(zhí)行,next命令簡寫。
18 for(i=1; i<=100; i++)
(gdb) n
20 result += i;
(gdb) n
18 for(i=1; i<=100; i++)
(gdb) n
20 result += i;
(gdb) c <--------------------- 繼續(xù)運(yùn)行程序,continue命令簡寫。
Continuing.
result[1-100] = 5050 <----------程序輸出。
Breakpoint 2, func (n=250) at tst.c:5
5 int sum=0,i;
(gdb) n
6 for(i=1; i<=n; i++)
(gdb) p i <--------------------- 打印變量i的值,print命令簡寫。
$1 = 134513808
(gdb) n
8 sum+=i;
(gdb) n
6 for(i=1; i<=n; i++)
(gdb) p sum
$2 = 1
(gdb) n
8 sum+=i;
(gdb) p i
$3 = 2
(gdb) n
6 for(i=1; i<=n; i++)
(gdb) p sum
$4 = 3
(gdb) bt <--------------------- 查看函數(shù)堆棧。
#0 func (n=250) at tst.c:5
#1 0x080484e4 in main () at tst.c:24
#2 0x400409ed in __libc_start_main () from /lib/libc.so.6
(gdb) finish <--------------------- 退出函數(shù)。
Run till exit from #0 func (n=250) at tst.c:5
0x080484e4 in main () at tst.c:24
24 printf("result[1-250] = %d \n", func(250) );
Value returned is $6 = 31375
(gdb) c <--------------------- 繼續(xù)運(yùn)行。
Continuing.
result[1-250] = 31375 <----------程序輸出。
Program exited with code 027. <--------程序退出,調(diào)試結(jié)束。
(gdb) q <--------------------- 退出gdb。
示例:
d=`date +%d`
echo "size" $'\t' "month" $'\t' "day" $'\t' "time" $'\t' "dir/file"
ls -l */* | awk '{if($5 > 0 && $7 == '$d') print $5 "\t" $6 "\t" $7 "\t" $8 "\t" $9}'
值得注意的是
d=`date +%d`, 這里的引號(hào)不是“;”右邊的鍵而是“tab”上面的那個(gè)