随笔 程序运行的基本原理

程序是如何运行,又是如何崩溃的?

正如标题所言,今天我们来聊聊程序是如何执行的?以及又是如何崩溃的?我们哼哧哼哧写的代码并不是程序,本质上不过是一个文本文件。即便我们将我们写的代码通过编译生成的可执行文件,本质也没有变,最多不过是一个优点特殊的文本文件。如果要程序真正的运行起来,就需要操作系统将我们的可执行文件加载到内存中,除此之外,操作系统还会额外的创建堆空间,栈空间以及供操作系统管理需要的数据结构,比如PCB。完成了上述的过程,我们写的代码才能被叫做程序,也就是我们熟知的进程。一个进程占用的内存主要分为4个部分:

  1. 代码空间

  2. 堆空间

  3. 栈空间

  4. 相关的数据结构需要的空间

在程序运行的过程中,内存占用不断变化的空间有两个一个是堆空间,一个是栈空间。那么两者有何不同呢?

两者的共同点就是都是用来存储程序运行过程中产生的临时数据的,只不过数据的生命周期不同罢了。在堆空间中,数据的生命周期是可以跨函数的,一般用于共享的场景,关于堆内存的管理,不同的语言有不同的管理策略,比如,C语言对堆内存的管理完全交给程序员自己管理,Java对堆内存的管理是交由垃圾回收器管理。而栈空间的数据是无法跨函数的,可见范围只能在一个函数内部,典型的代表就是我们熟知的局部变量。针对栈空间的管理,是基于一定的规则的,栈这种数据结构有一个特点,先进后出。每一次函数调用,就会在栈空间中创建一个栈帧,这个栈帧里面存放的数据就是当前这个函数中用到的局部变量。当一个函数执行完毕,就会将对应的栈帧弹出。由于栈的特点,就保证了正在执行的程序的栈帧总是位于栈顶。

上述描述的不过是,进程静态的样子,接下来描述进程如何被操作系统调度。进程由三种状态:

  1. 就绪态

  2. 运行态

  3. 阻塞态

当进程处于就绪态时,意味着一切准备就绪,只需要等待操作系统的调度就可以执行。运行态就是进程正在使用CPU执行指令,阻塞态就是因为需要等待某些资源,可能是IO,可能是锁,而暂时不被操作系统调度,一旦等待的资源就绪,就会进入就绪态,这个时候就可以被操作系统调度。

不过现代的操作系统,调度单元可不是进程,而是线程,但是线程不过是共享了大部分数据的进程而已。也常常被别人称为轻量级进程。具体怎么回事呢?创建一个线程,其实就是创建一个进程,但是我们知道创建进程需要分配代码空间,堆空间,栈空间,以及相关的数据结构需要的空间。而线程做的事情是复用父进程的代码空间,堆空间,创建一个额外的栈空间,以及供操作系统管理的线程相关的数据结构 -- TCB。从这个角度看,我们的线程确实要比进程轻量一些。

讲完了程序是如何运行的,我们来看看程序会因为什么原因导致程序崩溃。主要有两个原因,一个原因是自己写的代码有BUG,一种就是计算机资源不够。当代码有Bug时,当CPU执行了这段有代码的Bug时,可能立即崩溃。也可能因为堆内存的管理不当,导致堆内存不断扩大,达到操作系统的限制,导致程序崩溃,这种情况叫做内存泄漏。计算机的资源总是有限的,比如内存只有那么多,当我们的程序运行过程中,使用的内存超过了限制,也会导致程序崩溃。

相信通过这部分比较浅显的介绍你一定知道了程序是如何运行的,以及程序是如何崩溃的了,但是这段描述不够细节,如果你需要更深入的学习,可以看看《程序员的自我修养 -- 链接、装载与库》

相关推荐
超级码.里奥.农1 分钟前
零基础 “入坑” Java--- 七、数组(二)
java·开发语言
hqxstudying10 分钟前
Java创建型模式---单例模式
java·数据结构·设计模式·代码规范
挺菜的19 分钟前
【算法刷题记录(简单题)002】字符串字符匹配(java代码实现)
java·开发语言·算法
A__tao19 分钟前
一键将 SQL 转为 Java 实体类,全面支持 MySQL / PostgreSQL / Oracle!
java·sql·mysql
一只叫煤球的猫30 分钟前
真实事故复盘:Redis分布式锁居然失效了?公司十年老程序员踩的坑
java·redis·后端
猴哥源码33 分钟前
基于Java+SpringBoot的农事管理系统
java·spring boot
面朝大海,春不暖,花不开1 小时前
Java网络编程:TCP/UDP套接字通信详解
java·网络·tcp/ip
慕y2741 小时前
Java学习第十五部分——MyBatis
java·学习·mybatis
A__tao1 小时前
SQL 转 Java 实体类工具
java·数据库·sql
喝可乐的布偶猫1 小时前
Java类变量(静态变量)
java·开发语言·jvm