本文使用golang的syscall,os,golang.org/x/sys/unix包
1.main函數(shù)
main是程序的入口,golang中也亦是如此
啟動一個程序時啟動例程負責從內核獲取命令行參數(shù)和環(huán)境變量,維護到程序的內存布局中(后文描述)
2.exit
//import os
func Exit(code int)
使程序主動退出,令退出碼為指定值code,程序正常結束時返回碼為0 (在一般的shell中使用$?獲取)
- 執(zhí)行exit時 會使標準I/O進行關閉flush操作
- APUE中提到針對C語言,C99之前main終止前沒有顯式return或exit會導致退出嗎不確定
atexit函數(shù),golang中未實現(xiàn)
#include<stdlib.h>
int atexit(void (*func)(void)));
3.命令行參數(shù)
//import os
var Args []string
程序啟動時命令行跟隨的參數(shù)
4.C程序的存儲空間布局
- 正文段:CPU執(zhí)行的機器指令,該部分使可共享的,只讀的
- 初始化數(shù)據(jù)段: 包含了程序明確賦初值的變量,如C中已賦值的全局變量
- 未初始化的數(shù)據(jù)段:該段在程序啟動前,由內核將此段中數(shù)據(jù)刷為0(該段不部存放在磁盤文件中)
- 堆:運行時,動態(tài)存儲分配的資源位置
- 棧:運行時,自動變量以及函數(shù)調用時所需保存的信息都存于此處
- 高地址部分:存儲命令行參數(shù)和環(huán)境變量
shell中可使用size命令查看二進制程序的正文段,初始化段,bss段
5.共享庫
操作系統(tǒng)所支持的一種庫操作,使得程序與存儲中的共享庫連接,減小了程序的大小,但略微增加了程序執(zhí)行開銷(在程序第一次運行或每個共享庫第一次被調用)
golang共享庫 待補充。。
6.存儲空間分配
原文中提到的是malloc caloc realloc,實際在golang中應使用make new
//builtin
func make(t Type, size ...IntegerType) Type
func new(Type) *Type
7.環(huán)境變量
//import golang.org/x/sys/unix
func Getenv(key string) (value string, found bool) {
return syscall.Getenv(key)
}
func Setenv(key, value string) error {
return syscall.Setenv(key, value)
}
由[4.C程序的存儲空間布局],我們已知環(huán)境變量在棧之上(進程存儲空間頂部),且由一個**char的指針列表來維護,且該空間不可伸縮,當要新增環(huán)境變量時會導致一些存儲變化
分3種情況討論
- 刪除一個環(huán)境變量:直接刪除其環(huán)境列表中的指針,后續(xù)指針順次前移
- 修改一個環(huán)境變量:
- 修改后值變小:直接修改原key=value值
- 修改后值變大: 需要在堆中新分配一個存儲空間村kv,再修改指針表中其對應地址
- 增加一個環(huán)境變量:
- 第一次增加:再堆中分配一個空間存儲新的環(huán)境表,將老的環(huán)境表拷貝過來,然后在尾部追加本次待插入的key=value的指針和一個空指針,再將內核的environ指向該指針表
- 非第一次添加:realloc指針表,同上在尾部追加(原表尾會又一個空指針,利用這個)一個kv值的指針和一個空指針
8.setjmp,longjmp
C中跨越函數(shù)goto的高級玩法,通常適用于一些深層嵌套的函數(shù)
#include<sethmp.h>
int setjmp(jmp_buf env);
void longjmp(jmp_buf env, int val);
jmp_buf變量通常使用全局變量,是一個某種形式的數(shù)組,存儲恢復棧狀態(tài)時所需要的信息。
longjmp回跳時需要提供這個buf以便找到要恢復的位置。
longjmp還需要提供一個整型值,以通知setjmp的返回值,直接調用setjmp返回的值為0
longjmp后會拋棄掉調用setjmp的函數(shù)棧幀一下的所有棧幀
關于longjmp后變量值的問題:存放在存儲器中的值(通常為內存)保持longjmp時的值,而cpu和浮點寄存器的值恢復到setjmp時的狀態(tài)
9.資源限制
type Rlimit struct {
Cur uint64 //soft limit
Max uint64 //hard limit
}
func Getrlimit(resource int, rlim *Rlimit) (err error)
func Setrlimit(resource int, rlim *Rlimit) (err error)
Cur決定當前實際的限制值
關于rlimit結構,存在3個規(guī)則:
任何一個進程都可以更改Cur小于等于Max
任何一個進程都可以降低Max,但必須大于等于Cur,對非root是不可逆的
-
root可調大Max
resource 值 含義 //golang.org/x/sys/unix CONST
resource 值 含義
|RLIMIT_AS | 0x9|進程可用存儲空間最大值|
|RLIMIT_CORE | 0x4|core文件最大字節(jié)數(shù),0則阻止創(chuàng)建core文件|
| RLIMIT_CPU | 0x0|CPU時間最大量值,超過則發(fā)送SIGXCPU信號|
| RLIMIT_DATA | 0x2|數(shù)據(jù)段最大字節(jié)長度(初始化,RSS,堆)|
| RLIMIT_FSIZE | 0x1|可創(chuàng)建文件最大字節(jié)長度|
| RLIMIT_LOCKS | 0xa|一個進程可持有的文件鎖的最大數(shù)|
| RLIMIT_MEMLOCK | 0x8|使用MLOCK能鎖住的最大字節(jié)長度空間|
| RLIMIT_MSGQUEUE | 0xc|POSIX消息隊列最大存儲字節(jié)長度|
| RLIMIT_NICE | 0xd|Nice值可設置最大值|
| RLIMIT_NOFILE | 0x7|能打開的最大句柄數(shù)|
| RLIMIT_NPROC | 0x6|每個實際用戶ID可擁有最大進程數(shù)|
| RLIMIT_RSS | 0x5|RSS最大長度|
| RLIMIT_RTPRIO | 0xe|進程可通過sched_setscheduler 和 sched_setparam設置的最大實時優(yōu)先級。
| RLIMIT_RTTIME | 0xf|CPU時間限制,在非阻塞系統(tǒng)調用上的CPU時間消耗,到soft值時會收到SIGXCPU,超過hard值時會收到SIGKILL
| RLIMIT_SIGPENDING | 0xb|一個進程可排隊的最大信號數(shù)量|
| RLIMIT_STACK | 0x3|棧的最大字節(jié)長度|
| RLIM_INFINITY | -0x1|無限量值|