Linux线程栈空间大小详解 (linux 线程栈空间大小)

在Linux系统中,线程栈是一个很重要的概念,它是用来保存函数调用过程中所需要的数据和局部变量以及函数返回地址的空间,每个线程都拥有自己的线程栈。本文将详细介绍Linux线程栈空间大小的相关知识。

一、线程栈的概念

线程栈是进程中每个线程都拥有的内存空间,主要用于保存局部变量和函数调用时的数据。在Linux中,线程栈和进程栈、用户栈是等价的概念。线程栈的大小不同于虚拟内存空间的大小,线程栈的大小是由线程库来维护的。

二、线程栈的空间大小

在Linux系统中,线程栈的空间大小是通过线程库来维护的,一般情况下,线程栈的大小是固定的。Linux系统默认的线程栈大小为2MB,但是可以通过修改内核参数或者线程库的一些函数来改变线程栈的大小。

1. 修改内核参数

在Linux系统中,可以通过修改内核参数来改变线程栈的大小。可以使用命令“ulimit -s ”来修改线程栈的大小,其中指的是栈的大小,单位是KB。需要注意的是,修改内核参数需要使用root权限。

2. 使用线程库

除了修改内核参数,也可以使用线程库的函数来修改线程栈的大小。例如,可以使用pthread_attr_setstacksize()函数来设置线程栈的大小,该函数的原型如下:

int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize);

其中,attr是一个pthread_attr_t类型的指针,stacksize是线程栈的大小,以字节为单位。

三、线程栈大小的影响

线程栈的大小会影响线程的性能和稳定性,如果线程栈的大小过小,会导致程序崩溃或者出现无法预测的错误。如果线程栈的大小过大,会浪费内存资源,降低程序的运行效率。

1. 线程栈大小过小

如果线程栈的大小过小,会导致程序崩溃或者出现无法预测的错误。这是因为函数的返回地址和局部变量都保存在线程栈中,如果线程栈的空间不足以保存这些数据,就会导致栈溢出的错误。此外,线程栈的大小还会影响递归函数的调用深度,如果线程栈的大小过小,递归函数可能会导致栈溢出错误。

2. 线程栈大小过大

如果线程栈的大小过大,会浪费内存资源,降低程序的运行效率。线程栈的大小会占用虚拟内存空间,并且需要在内存中分配实际的物理内存,如果线程栈的大小过大,就会浪费大量的内存资源。

四、

相关问题拓展阅读:

Linux里面JVM内存怎么设置

jar包启动时指定对应参数,比如我的工程启动银答命令就是这样的

启动命令,打码部分为工程名

常见参数如下

1.-Xms:初始堆大小。只锋宏慧要启动,就占用的堆大小。

2.-Xmx:更大堆大小。java.lang.OutOfMemoryError:Java heap这个错误可以通过配置-Xms和-Xmx参数来设置。

3.-Xss:栈大小分配。栈是每个线程私有的区域,通常只有几百K大小,决定了函数调用的深度,而局部变量、参数都分配到栈上。

当出现大量局部变量,递归时,会发生栈空间OOM(java.lang.StackOverflowError)之类的错误。

4.XX:NewSize:设置新生代大小的绝对值。

5.-XX:NewRatio:设置年轻代和年老代的比值。比如设置为3,则新生代:老年代=1:3,新生代占总heap的1/4。

6.-XX:MaxPermSize:设置持久代大小。

java.lang.OutOfMemoryError:PermGenspace这个OOM错误需要合理调大PermSize和MaxPermSize大小。

7.-XX:SurvivorRatio:年轻代中Eden区与两个Survivor区的比值。注意,Survivor区有form和to两个。比如设置为8时,那么eden:form:to=8:1:1。

8.-XX:HeapDumpOnOutOfMemoryError:发生OOM时转储堆到文件,这是一个非常好的诊断方法。

9.-XX:HeapDumpPath:导出堆的转储文件路径。

10.-XX:OnOutOfMemoryError:OOM时,执行一个脚本,比如发送邮件报警,重启程序。后绝弊面跟着一个脚本的路径。

一、堆内存相关配置

设置历漏堆初始值

指令1:-Xms2g

指令2:-XX:InitialHeapSize=2023m

设置堆区更大值

指令1:`-Xmx2g`

指令2: -XX:MaxHeapSize=2023m

缩小堆内存的时机

-XX:MaxHeapFreeRatio=70//堆内存使用率大于70时扩张堆内存,xms=xmx时该参数无效,默认值70

扩张堆内存的时机

-XX:MinHeapFreeRatio=40//堆内存使用率小于40时缩减堆内存,xms=xmx时该参数无效,默认值40

新生代内存配置

指令1:-Xmn512m

指令2:-XX:MaxNewSize=512m

2个survivor区和Eden区大小比率

指令:-XX:SurvivorRatio=6 //S区和Eden区占新生代比率为1:6,两个S区2:6

新生代和老年代的占比

-XX:NewRatio=4 //表示新生代:老年代 = 1:4 即老年代占整个堆的4/5;默认值=2

二、方法区内存配置常用参数

初始化的Metaspace大小,

-XX:MetaspaceSize :

Metaspace更大值

-XX:MaxMetaspaceSize

三、线程栈内存配置常用参数

每个线程栈更大值

指令1:-Xss256k

指令2:-XX:ThreadStackSize=256k

注意:

栈肢扰烂设置太大,会导致线程创建减少。

栈设置小,会导致深入不够,深度的递归会导致栈溢出。

建议栈深度设置在

四、配置垃圾收集器

Serial垃圾收集器(新生代)

开启:-XX:+UseSerialGC

关闭:-XX:-UseSerialGC

//新生代使用Serial 老年代则使用SerialOld

ParNew垃圾收集器(新生代)

开启 -XX:+UseParNewGC

关闭 -XX:-UseParNewGC

//新生代使用功能ParNew 老年代则使用功能CMS

Parallel Scavenge收集器(新生代)

开启 -XX:+UseParallelOldGC

关闭 -XX:-UseParallelOldGC

//新生代使用功能Parallel Scavenge 老年代李滑将会使用Parallel Old收集器

ParallelOl垃圾收集器(老年代)

开启 -XX:+UseParallelGC

关闭 -XX:-UseParallelGC

//新生代使用功能Parallel Scavenge 老年代将会使用Parallel Old收集器

CMS垃圾收集器(老年代)

开启 -XX:+UseConcMarkSweepGC

关闭 -XX:-UseConcMarkSweepGC

G1垃圾收集器

开启 -XX:+UseG1GC

关闭 -XX:-UseG1GC

五、GC策略配置

GC并行执行线程数

-XX:ParallelGCThreads=16

新生代可容纳的更大对象

-XX:PretenureSizeThreshold=//大于此值的对象直接会分配到老年代,设置为0则没有限制。 //避免在Eden区和Survivor区发生大量的内存复制,该参数只对Serial和ParNew收集器有效,Parallel Scavenge并不认识该参数

进入老年代的GC年龄

进入老年代最小的GC年龄

-XX:InitialTenuringThreshol=7 //年轻代对象转换为老年代对象最小年龄值,默认值7,对象在坚持过一次Minor GC之后,年龄就加1,每个对象在坚持过一次Minor GC之后,年龄就增加1

进入老年代更大的GC年龄

-XX:MaxTenuringThreshold=15 //年轻代对象转换为老年代对象更大年龄值,默认值15

六、GC日志信息配置

配置GC文件路径

-Xloggc:/data/gclog/gc.log//固定路径名称生成 -Xloggc:/home/GCEASY/gc-%t.log //根据时间生成

滚动生成日志

日志文件达到一定大小后,生成另一个文件。须配置Xloggc

开启 -XX:+UseGCLogFileRotation

关闭 -XX:-UseGCLogFileRotation

-XX:NumberOfGCLogFiles=4 //滚动GC日志文件数,默认0,不滚动 -XX:GCLogFileSize=100k //GC文件滚动大小,需配置UseGCLogFileRotation,设置为0表示仅通过jcmd命令触发

进程内核栈,用户栈及 Linux 进程栈和线程栈的区别

总结:线程栈的空间悔正指开辟在所属进程的堆区,线程与其所属的进程共享进程的用户空间,所以线程栈之间可以互访。线程栈的起始地址和大小存放在pthread_attr_t 中,栈的大小并不是用来判断栈是否越界,而是用来初始化避免栈溢出的缓冲区的大小(或者说安全间隙清猜的大小)

进程内核栈、用户栈

1.进程的堆栈

内核在创建进程的时候,在创建task_struct的同事,会为进程创建相应的堆栈。每个进程会有两个栈,一个用户栈,存在于用户空间,一个内核栈,存 在于内核空间。当进程在用户空间运行碧配时,cpu堆栈指针寄存器里面的内容是用户堆栈地址,使用用户栈;当进程在内核空间时,cpu堆栈指针寄存器里面的内 容是内核栈空间地址,使用内核栈。

2.进程用户栈和内核栈的切换

当进程因为中断或者系统调用而陷入内核态之行时,进程所使用的堆栈也要从用户栈转到内核栈。

进程陷入内核态后,先把用户态堆栈的地址保存在内核栈之中,然后设置堆栈指针寄存器的内容为内核栈的地址,这样就完成了用户栈向内核栈的转换;当进程从内 核态恢复到用户态之行时,在内核态之行的最后将保存在内核栈里面的用户栈的地址恢复到堆栈指针寄存器即可。这样就实现了内核栈和用户栈的互转。

那么,我们知道从内核转到用户态时用户栈的地址是在陷入内核的时候保存在内核栈里面的,但是在陷入内核的时候,我们是如何知道内核栈的地址的呢?

关键在进程从用户态转到内核态的时候,进程的内核栈总是空的。这是因为,当进程在用户态运行时,使用的是用户栈,当进程陷入到内核态时,内 核栈保存进程在内核态运行的相关信心,但是一旦进程返回到用户态后,内核栈中保存的信息无效,会全部恢复,因此每次进程从用户态陷入内核的时候得到的内核 栈都是空的(为什么?)。所以在进程陷入内核的时候,直接把内核栈的栈顶地址给堆栈指针寄存器就可以了。

3.内核栈的实现

内核栈在kernel-2.4和kernel-2.6里面的实现方式是不一样的。

在kernel-2.4内核里面,内核栈的实现是:

Union task_union {

Struct task_struct task;

Unsigned long stack;

};

其中,INIT_STACK_SIZE的大小只能是8K。

内核为每个进程分配task_struct结构体的时候,实际上分配两个连续的物理页面,底部用作task_struct结构体,结构上面的用作堆栈。使用current()宏能够访问当前正在运行的进程描述符。

注意:这个时候task_struct结构是在内核栈里面的,内核栈的实际能用大小大概有7K。

内核栈在kernel-2.6里面的实现是(kernel-2.6.32):

Union thread_union {

Struct thread_info thread_info;

Unsigned long stack;

};

其中THREAD_SIZE的大小可以是4K,也可以是8K,thread_info占52bytes。

当内核栈为8K时,Thread_info在这块内存的起始地址,内核栈从堆栈末端向下增长。所以此时,kernel-2.6中的current宏是需要 更改的。要通过thread_info结构体中的task_struct域来获得于thread_info相关联的task。更详细的参考相应的 current宏的实现。

struct thread_info {

struct task_struct *task;

struct exec_domain *exec_domain;

__u32 flags;

__u32 status;

__u32 cpu;

… ..

};

关于linux 线程栈空间大小的介绍到此就结束了,不知道你从中找到你需要的信息了吗 ?如果你还想了解更多这方面的信息,记得收藏关注本站。


数据运维技术 » Linux线程栈空间大小详解 (linux 线程栈空间大小)