现代化程序开发笔记(5)——生命周期管理
本系列文章以我的个人博客的搭建为线索(GitHub 仓库:Evian-Zhang/evian-blog),记录我在现代化程序设计中的一些笔记。在这篇文章中,我将讨论的是现代语言的变量生命周期管理机制。
背景
我们知道,在一个程序运行的时候,任何一个使用的变量在内存中都会占有一定的空间。而除去特殊的静态数据区,在大多数操作系统中,变量要么储存在栈上,要么储存在堆上。创造变量有两种方式,一种是直接在块级作用域内声明局部变量,这种变量是分配在栈上的,另一种则是调用操作系统提供的内存分配函数如malloc
等,这种变量是分配在堆上的。而这两种区域也提供了回收变量的方法。当块级作用域结束的时候,其栈上的变量都被回收;当我们调用操作系统提供的内存回收函数如free
等,在堆上的变量也就可以得到回收。
我们为什么需要变量内存空间的回收呢?这是因为,在一个进程被创建的时候,操作系统会为该进程分配虚拟内存空间,而虚拟内存空间是与物理内存存在映射的。一个进程的栈和堆实际上都是在这个虚拟内存中的。而物理内存是存在上限的,一般的手机是4GB到8GB,个人电脑则有可能到16GB,服务器的内存则更大,但都存在上限。笼统来说,在一个进程的虚拟内存中,每个存储区域的状态分为两种,一种是被进程使用的,一种是未被进程使用的。栈的增长,malloc
的调用,都是将标记为未被使用的存储区域标记为被使用,而栈的收缩,free
的调用,则是将相应被标记为已使用的存储区域重新标记为未被使用。
如果我们不断地调用malloc
,或者在栈上声明巨多的局部变量,而不去释放相应的内存,那么虚拟内存中越来越多的存储区域被标记为已使用,也就占用了越来越多的物理内存。一旦占用的内存大小超过了操作系统设置的阈值,那么常见的操作系统都会直接结束掉当前的进程。
因此,我们需要垃圾回收机制。调用malloc
, free
, 在栈上分配回收变量,这些都是操作系统的角度,从编程语言的角度来看,当我们声明一个局部变量,或者调用malloc
,那么代表一个变量的生命周期开始了。而我们的块作用域结束,或者调用free
,则代表一个变量的生命周期结束了。
常见生命周期管理机制
在栈上分配的变量由于操作系统直接管理,所以不需要编程语言的干涉;在堆上分配的变量则需要编程语言或开发者手动管理,所以接下来,我们讨论的是如何管理在堆上分配的变量。
手动内存管理
手动内存管理是最直接的方法。当我们需要一块内存区域的时候,直接malloc
,并返回给我们指向这块内存区域的指针。我们可以在多个函数间,甚至多个线程间传递这个指针,但其在堆上的区域大小始终不变。当开发者决定这个变量寿终正寝的时候,就调用free
,然后就没有然后了。
但是,然后真的没有然后了吗?开发者也是有可能犯错的。关于free
,开发者最容易犯的两个错是:对于同一个指针地址free
了两次,以及在free
了之后仍然使用了这个变量。
Double free
我们之前提到,free
的作用是将堆上的内存释放,将标记为已使用的内存重新标记为未使用。那如果是未使用的内存,被free
的时候就会产生错误,使程序崩溃,如:
void double_free() {int *ptr = (int *)malloc(16 * sizeof(int));// do something with ptrfree(ptr);// do some other things without ptrfree(ptr); // BOOM
}
在第二次free(ptr)
的时候,由于ptr
的值并没有变,所以其指向的仍然是之前那个已经被释放的内存区域,所以就会产生程序的崩溃。
由于操作系统自身对free
功能的实现,会有各种各样的漏洞,Double free
的问题也有可能会产生一些漏洞,可以参考CTF wiki的Fastbin Double Free。
Use after free
比起Double free
问题,这个问题就更可怕了。它指的是以下情景:
void use_after_free() {int *ptr = (int *)malloc(16 * sizeof(int));// do something with ptrfree(ptr);// do some other things without ptrint a = ptr[3];ptr[4] = 9;
}
当我们释放一个指针指向的堆上的空间时,其内容有可能不会被清空,那么如果开发者没注意,在之后又用到了这块区域,那么就会产生不可知的情况,也可能会产生安全漏洞,可以参考CTF wiki的Use After Free。
为了解决这种漏洞的问题,所有的使用汇编语言、C语言或C++语言的开发者都会有这种常识,将指针free
之后要置为NULL
!也就是
void null_after_free() {int *ptr = (int *)malloc(16 * sizeof(int));// do something with ptrfree(ptr);ptr = NULL;
}
这虽然不能避免之后的Double free
或Use after free
使程序崩溃,但能有效避免被恶意地篡改程序产生漏洞。
RAII
对于手动内存管理的OOP语言来说,正如我们刚刚看到的,会在开发者一不留神的情况下就产生许多严重的安全漏洞。因此,一种叫RAII(Resource Acquisition Is Initialization)的开发方案被广泛地使用。
我们知道,在C++中,如果是分配在栈上的类对象,那么在其被创建时会被调用构造函数,在离开作用域时会调用析构函数,比如说:
class PointerWrapper {
public:PointerWrapper() {std::cout << "Constructor of PointerWrapper is called." << std::endl;}~PointerWrapper() {std::cout << "Destructor of PointerWrapper is called." << std::endl;}
}void foo() {PointerWrapper pointer_wrapper;
}
那么,当调用foo
时,栈上会分配pointer_wrapper
这个类的对象,并调用其构造函数,并输出"Constructor of PointerWrapper is called."。当foo
结束时,pointer_wrapper
对象会被回收,并调用其析构函数,并输出"Destructor of PointerWrapper is called."。利用C++的这个机制,我们可以将之前万恶的指针包在这个类里:
class PointerWrapper {int *ptr;
public:PointerWrapper() {this->ptr = new int[16];}~PointerWrapper() {if (this->ptr != nullptr) {delete[] this->ptr;this->ptr = nullptr;}}
}void foo() {PointerWrapper pointer_wrapper;
}
由于C++提供的有效的栈上内存回收的机制,我们可以避免自己写free
或者delete
,也就解决了很大的问题。事实上,C++的智能指针就是按照这种理念设计的。
引用计数
引用计数(Reference Counting)是由编程语言来控制内存分配与释放的一个最基本,也是最简单的想法。它的想法就是,如果一个变量没有人用了,那么就可以释放了。具体而言,每个新开辟的内存区域会被维护一个引用计数器,每当有一个变量引用该内存区域的时候,它的引用计数器就会自增,如果有变量不再引用这块内存区域的话,引用计数器就会自减。当一个变量的引用计数为0时,就会自动释放这个变量。
Swift就是使用引用计数来进行变量生命周期管理的一个语言,使用它官方教程中的一个例子:
class Person {let name: Stringinit(name: String) {self.name = nameprint("\(name) is being initialized")}deinit {print("\(name) is being deinitialized")}
}
var reference1: Person?
var reference2: Person?
var reference3: Person?
reference1 = Person(name: "John Appleseed") // [1]
// Prints "John Appleseed is being initialized"
reference2 = reference1 // [2]
reference3 = reference1 // [3]
reference1 = nil // [4]
reference2 = nil // [5]
reference3 = nil // [6]
// Prints "John Appleseed is being deinitialized"
涉及到引用计数管理的一共有六步,在代码中都进行了标注。其中:
- 步骤[1]中,操作系统会在堆上分配一个
Person
类型的对象,然后reference1
对这块内存区域进行了一个引用,所以此时其引用计数器为1。 - 步骤[2]中,
reference2
通过reference1
,再次引用了这块内存区域,此时这块内存区域一共有reference1
和reference2
两个引用,所以其引用计数器为2。 - 步骤[3]中,
reference3
也类似地引用了这块内存区域,所以引用计数器此时为3。 - 步骤[4]中,
reference1
不再引用这块内存区域,所以引用计数器自减,变成了2。 - 步骤[5]中,类似地,引用计数器变成了1。
- 最后,在步骤[6]中,引用计数器变成了0,所以操作系统调用了这个对象的析构函数,并释放了这块内存区域。
一切看上去都是这么美好,但这就没问题了吗?并不,引用计数会有两个需要考虑的问题。
第一,引用计数器本身实际上也是一个变量,需要语言的运行时对它进行操控(自增或自减)。这在单线程中是很简单的,但是在多线程中,一块内存区域可能会被多条线程引用,在每条线程内部会对这块内存区域新增引用、减少引用,这样就会导致引用计数器上产生竞争条件。所以,引用计数器需要加上锁,或者使用原子操作,而这实际上是会使性能有所降低的。
第二,就是循环引用的问题。设想一个双向链表,每一个节点同时保存了前一个节点和后一个节点的引用。那么,假设节点A与节点B相连,那么节点A拥有节点B的引用,节点B也拥有节点A的引用。那么,编程语言的运行时是永远不能释放这两个节点的。这是因为,假设要先释放某一个节点,那么其必要条件就是这个节点的引用计数器为0。但是另一个节点仍然存在,并且保持着对这个节点的引用,所以这个节点的引用计数器必然不能为0,产生矛盾。用现实中的例子而言,就像是一个主人拿绳子牵着狗。我们可以通过主人,获得它的狗,所以主人拥有狗的引用;同时,我们也能通过狗,获得它的主人,狗也拥有主人的引用。这就会导致一种循环引用。
强/弱引用
破解循环引用的方法就是,告诉语言的运行时,某一方拥有另一方的引用时,不要自增引用计数器。比如说,主人对运行时说,我牵这条狗的时候,这条狗的引用计数要自增;但这条狗被我牵的时候,我自身的引用计数器不要自增。这样的话,当没有人知道这个人和这条狗的时候,主人此时的引用计数就为0了,然后主人被释放了,此时狗的引用计数器就会随之自减,也变为0,这样也能释放狗了。这种解决方案被称为强引用和弱引用。一般的会增加引用计数器的引用,被称为强引用,而特殊的不会增加引用计数器的引用,被称为弱引用。
强引用和弱引用除了在循环引用的时候可以有效解决问题,在另一种情况下也能很有效地解决问题。试想下面这种情况:
let client = Client()
class Person {var book: Book?func fetch() {client.fetch(completionHandler: { book ->self.book = book})}
}
在这种回调函数的情况下,乍一看似乎没什么问题,但是,如果在client
成功拉取到book
时,请求发起这个操作的Person
对象已经不再需要了了,也就是说此时只有completionHandler
这个闭包保持着对这个对象的引用。那么,即使已经赋值了,但此时的赋值就没用了。但是,改写成弱引用就显得更优雅一些:
let client = Client()
class Person {var book: Book?func fetch() {client.fetch(completionHandler: { [weak self] book ->guard let self = self else { return }self.book = book})}
}
上述的语法中[weak self]
表示这个这个闭包只持有self
的弱引用。那么,当获得返回值时,如果这个对象已经被析构了,那么guard
语句会让闭包直接返回,不仅不需要额外的赋值操作,同时也不会一直持有对象的引用,使对象在正确的时候被析构。
垃圾回收器
Python同样使用了引用计数的变量生命周期管理办法,所以它也同样遇到了循环引用的问题。与Swift不同,Python并没有使用强弱引用的机制,而是引入了一个垃圾回收器,其详细算法可以参考这篇博客。
大体来说,Python对于循环引用的处理办法是,每隔一段时间运行一下垃圾回收器,而垃圾回收器通过特定的算法,找出此时由于循环引用而没有被释放掉的变量,然后释放。其具体的算法也并不难,就是首先找出那些有可能存在循环引用的变量,然后让他们之间内部都不互相引用,这样,引用计数器仍不为0的代表被外界所引用,所以不应被释放,而为0的则代表是在内部循环引用的,并且外部没有引用他们的变量了。
垃圾回收
除了手动内存管理,引用计数以外,还有一种变量生命周期管理的方法,就是垃圾回收。刚刚我们提到了,Python为了解决引用计数无法解决的循环引用问题,也引入了垃圾回收机制。所谓垃圾回收机制就是,语言的运行时每隔一段时间,调用一次垃圾回收器,垃圾回收器利用垃圾回收算法确定应该释放的变量,并将其释放。它的核心就在于垃圾回收算法。同时,无论垃圾回收算法如何,使用垃圾回收机制来管理变量生命周期的语言都无法避免的一点就是,如果采用这种语言编写一些服务器程序,并且开发者没有优化到位,那么每隔一段时间就会卡一下,因为被用来垃圾回收。因此,使用垃圾回收机制的语言开发的开发者,往往最津津乐道的,就是如何优化垃圾回收机制,让程序丝滑运行。
JavaScript
严格来说,ECMAScript并没有规定垃圾回收的策略,所以这里应该是具体每种运行时的实现。最常见的JavaScript运行时无非Google的V8引擎和Apple的JavaScriptCore引擎。但JavaScriptCore的资料好像有点少,所以我找的是V8引擎的垃圾回收策略,可以参考这篇文章。
总体而言,V8引擎采用的是分代垃圾回收策略。在实际编程中,有的变量总是被频繁地申请然后销毁,而有的变量则常驻内存。因此,对于不同的变量,应该采用不同的垃圾回收策略,所以V8就对变量分代,分为new generation和old generation。不同的代采用不同的垃圾回收策略,这就叫分代垃圾回收策略。
对于new generation,V8采用的是Scavenge算法,总体而言就是用空间换时间的一种策略,十分适合频繁申请释放的空间;对于old generation,V8则采用的是标记清除算法和标记整理算法,这些算法虽然不如Scavenge算法快,但是更适合内存的管理,可以减少内存碎片现象。对于具体的算法,这些都是经过层层优化的策略,这篇文章里还是主要注重于不同策略的讨论。
JVM
和JavaScript类似,JVM标准也没有规定垃圾回收的策略,所以不同的虚拟机实现中也有不同的垃圾回收策略。而基于JVM的语言,如Java和Kotlin等,往往没有语言自身的垃圾回收,而是依赖于JVM的垃圾回收。
JVM最常用的实现,Hotspot虚拟机,采用的依然和V8类似,是分代回收策略。但是,具体的策略,如并行串行等,JVM提供了运行参数,可以让用户在实际运行的时候调配。
Rust
Rust的变量生命周期管理机制是如此特殊,以至于它只能单独列为一类。
从堆上资源分配与释放的角度来看,Rust语言默认内置RAII模式。在一般情况下,我们能直接操作的变量,都是直接分配在栈上的,而栈上的变量,也可能拥有堆上的指针。当栈上的变量被释放时,会自动释放堆上的空间,这和我们之前提到的RAII模式相同。比方说:
struct MyStruct { }
struct PointerWrapper {something_on_heap: Box<MyStruct>,something_on_stack: MyStruct
}
impl PointerWrapper {fn new() -> Self {Self {something_on_heap: Box::new(MyStruct::new()),something_on_stack: MyStruct::new()}}
}
fn foo() {let pointer_wrapper = PointerWrapper::new();
}
在这个例子中,当我们调用foo
函数,会是一个什么过程呢?
- 在栈上申请
PointerWrapper
大小的一块区域 - 调用
PointerWrapper::new()
- 调用
Box::new()
,在堆上申请MyStruct
大小的一块区域 - 调用
MyStruct::new()
- 返回
MyStruct
类型的对象,其内存处于第3步申请的堆内空间里 - 返回
Box
类型的对象,其可以看作是一个指针,此时这个指针位于第1步申请的栈内空间里 - 调用
MyStruct::new()
- 返回
MyStruct
类型的对象,其内存处于第1步申请的栈内空间里 - 返回
PointerWrapper
类型的对象,其内存处于第1步申请的栈内空间里
由此可见,只有Box
对象指向的在堆上,其他都在栈上。在栈上最大的好处,就是可以直接由操作系统来管理内存。那么,假如我们、像foo
一样,什么也不做就结束了,那么退出作用域的时候会是什么过程呢?
- 调用
PointerWrapper
实现的Drop
trait的drop
函数 - 调用
Box
实现的Drop
trait的drop
函数 - 调用
MyStruct
实现的Drop
trait的drop
函数,什么也不做,直接返回 Box
实现的Drop
trait的drop
函数将之前申请的堆上的空间释放- 调用
MyStruct
实现的Drop
trait的drop
函数,什么也不做,直接返回 PointerWrapper
实现的Drop
trait的drop
函数什么也不做,直接返回- 栈回缩,清空
由此可见,Box
就是我们之前提到的RAII模式的一个实践。
这种方案看上去实现起来很简单嘛!那为什么之前的几种语言不采用呢?这不是易如反掌吗?这种方案看上去当然简单,但如果只是单纯用这种方案,就会产生麻烦的情况。我们在这个例子中,foo
只是创建了这个变量,什么也不做。那么,如果foo
将这个变量赋值给了别的变量呢?如果是传递给别的线程,别的线程结束之前这个函数已经结束了呢?
我们一个一个来看,如果赋值给了别的变量,那么,如果在C++中,会是什么情况呢?
class MyStruct { };
class MyStruct2 {
public:MyStruct *my_struct;
};
void foo(MyStruct2 *a, MyStruct2 *b, MyStruct2 *c) {MyStruct my_struct;a->my_struct = &my_struct;b->my_struct = &my_struct;c->my_struct = &my_struct;
}
这种方案是绝对错误的,因为一旦栈释放了,那么my_struct
的地址就无效了,那么a
, b
, c
的my_struct
字段都会有非法的引用了。
即使my_struct
通过new
在堆上创建,那么究竟是a
来释放,还是b
,抑或是c
呢?反正我知道,肯定不是foo
.
如果传递给了别的线程,那么效果更简单,在栈上创建的变量在函数结束的时候自动释放,别的线程也就有了一个非法引用,就会产生谁也不知道怎样的行为。
这一切,都是因为RAII模式中,把堆上变量的释放权交给了在栈上的变量,而栈上变量的释放权却是由操作系统决定的,就会产生一些意外的后果,所以别的语言都不会采用这种模式。
而Rust则是通过了所有权来完成这种管理。Rust的思想很简单,不管是在栈上还是在堆上,它始终是个变量,那么给变量规定一个主人就好了。主人负责它的空间申请,也负责它的空间释放。这种所有权通过转交,可以在函数、线程之间传递,可以很妙地解决这个问题。
具体而言,Rust规定每个变量都有它的主人,比如说:
fn bar1(a: &A) { }
fn bar2(a: A) { }fn foo() {let a = A::new();let b = &a;let c = a;bar1(c);bar2(c);
}
在foo
的第一行,栈上出现了一个A
的对象,这个对象可能还持有堆上的一部分区域,它的主人是a
。我们可以通过访问a
来访问这块内存区域。通过第二行,这块内存区域的主人并没有变,仍然是a
,但是b
持有对这块内存区域的引用。但b
出作用域的时候,并不会导致这个内存区域的释放。通过第三行,a
将所有权转移给c
,所以我们可以通过c
访问这块内存区域了,但是通过a
来访问就会在编译器发生错误。而bar1
接受的是A
类型的引用,所以在bar1
的作用域内,即使a
出作用域,也不会释放之前那块内存区域。bar2
则是直接接收A
类型的值,也就是说,通过bar2(c)
这一行,c
又将所有权转移给了bar2
的a
,当bar2
的a
出作用域时,这块内存终于得到了释放。
通过所有权机制,Rust很巧妙地在保证了RAII模式的同时,解决了实际编程开发中的一些问题。但是,有时候还是会需要多重所有权的,所以Rust也有Rc
, Arc
这些引用计数的类型,但本质上对内存的管理,还是让人轻松了很多的。
如若内容造成侵权/违法违规/事实不符,请联系编程学习网邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
相关文章
- SSM整合详细配置
以一个从数据库中查询数据为例,来一步一步总结ssm整合内容!会用到注解+xml的方式 文章目录一、dao层1、编写实体类2、编写dao接口(MyBatis框架不用写实现类)3、编写xml文件(不再写SqlMapConfig.xml,直接写到applicationContext.xml里面)4、dao层编写完毕,进行单元测试二…...
2024/5/2 17:11:13 - ARM9嵌入式Linux开发-嵌入式Linux根文件系统概述
Linux中一切皆文件! 是指:在Linux系统中,各个部分都可把它看成是一个文件,包括了所有的硬盘分区、目录、软盘、CD-ROM光盘和其他存储介质,以及显示器和打印机等硬件设备都可被看成一个文件。 从本质上而言,用户的一切工作就是对文件的操作。嵌入式Linux文件系统嵌入式…...
2024/4/24 14:14:00 - Node慕课网学习笔记(三)
1. koa2 的安装与使用新建文件夹 npm init npm i koa --save代码演示 新建 index.js 文件const Koa = require(koa) // commonjs 模块化规范 const app = new Koa()// ctx context 上下文 app.use(async (ctx) => {ctx.body = hello world })app.listen(3000) // web se…...
2024/4/29 4:49:26 - Linux.远程登录管理
Linux.远程登录管理目录: 一、虚拟机网络配置1.桥接模式(Briged)2.NAT模式(网络地址转换)3.Host-Only模式一、虚拟机网络配置虚拟机网络指通过软件模拟的具有完整硬件系统功能的、运行在一个完全隔离环境中的完整计算机系统所搭建构成的网络平台。通常上我们理解的网络是由…...
2024/4/27 0:29:07 - docker安装phpmyadmin
一、安装docker 1.下载docker-18.03.0-ce.tar 下载地址:https://download.docker.com/linux/static/stable/x86_64/压缩包里可以直接复制到服务器,可以不用下载 2.解压 tar xvf /docker-18.03.0-ce.tar3.将解压后的docker命令复制到/usr/bin cp ./docker/* /usr/bin/4.启动:…...
2024/4/27 11:16:39 - Chapter5_Speaker_Verification
文章目录1 Task Introduction2 模型架构3 模型介绍3.1 i-vector3.2 d-vector3.3 x-vector3.4 more4 End to End 本文为李弘毅老师【Speaker Verification】的课程笔记,课程视频youtube地址,点这里👈(需翻墙)。 下文中用到的图片均来自于李宏毅老师的PPT,若有侵权,必定删除…...
2024/4/28 15:36:28 - ftp 服务器 客户端,挖掘出7个好用的ftp 服务器 客户端
推荐一:IIS7服务器管理工具 IIS7服务器管理工具是一款windows全系、Linux系统下链接并操控VPS、VNC、FTP等远程服务器、云服务器。 界面简单明了,操作易上手,功能强大,支持批量导入服务器,并批量打开,多窗口化管理,除此之外,加载本地硬盘、硬盘映射、加载服务器的声音,…...
2024/4/15 3:21:01 - 从头来第五步正常使用服务器(Tomcat)使用IDEA开发前后端
1.Apache Tomcat和IDEA 简单的说tomcat就是一个小型的本地的服务器,便于程序员调试程序,观察网站。简介 环境 重要目录Tomcat是由Apache软件基金会属下Jakarta项目开发的Servlet容器,按照Sun Microsystems提供的技术规范,实现了对Servlet和JavaServer Page(JSP)的支持,并…...
2024/4/15 3:21:01 - 事件循环,微任务,宏任务
转载于:博客(终于明白这几个概念了)...
2024/4/30 12:19:48 - HBuilderX安装使用教程
HBuilderX安装使用教程HBuilderX是HBuilder的升级版。它是是DCloud(数字天堂)推出为前端开发者服务的通用IDE,或者称为编辑器。HBuilderX的功能从下图可以直观的了解个大概:官网地址:https://ask.dcloud.net.cn下载https://www.dcloud.io/hbuilderx.html说明:HBuilderX正…...
2024/4/21 10:07:41 - 事件执行队列
...
2024/4/24 14:13:59 - python爬取自如网房源信息
前言 本文的文字及图片来源于网络,仅供学习、交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理。 作者: Star_Zhao PS:如有需要Python学习资料的小伙伴可以加点击下方链接自行获取http://t.cn/A6Zvjdun 本次爬取自如网房源信息所用到的知识点:r…...
2024/4/24 14:13:58 - 虚基类和虚继承
class A { public: private:int ma; };class B:virtual public A { public: private:int mb; };这是最简单的虚继承的例子,下面是A和B的内存布局:此时A属于虚基类,但是他的内存布局还是不变的。 对于B,他的内存布局中多了一个vbptr指针,指向的是下面的vbtable表。vbtable中…...
2024/4/30 4:34:14 - Java 字节输入流与字节输出流
一、ASCII码概念 所有的数据存放在计算机中都是以数字的形式存放的。 所以字母就需要转换为数字才能够存放。 比如A就对应的数字65,a对应的数字97. 不同的字母和符号对应不同的数字,就是一张码表。 ASCII是这样的一种码表。 只包含简单的英文字母,符号,数字等等 二、以字节…...
2024/4/29 12:04:47 - Maven的常用命令与生命周期
清理命令:clean 把根目录下的target目录进行删除编译命令 compile 把文件进行编译,即生成target目录。单元测试:test,对代码进行运行,且类名需要以Test结尾打包命令:package在target目录下回处存在打包后的jar包打包到本地仓库:mvn install在本地仓库当中会生成器jar包m…...
2024/5/2 23:22:15 - volatile的实现原理以及应用场景
volatile的实现原理以及应用场景 volatile是轻量级的synchronized,但是volatile不会引起线程的上下文切换和调度。 共享变量的可见性 volatile在多核处理器进行开发时保证了共享变量的可见性,即当一个线程修改这个变量时,其他线程能立马得到最新修改的值。 1. volatile的硬件…...
2024/5/3 1:09:07 - shell脚本编程笔记(一)—— shell简介与变量
一、 shell简介1. shell的类型系统启用什么样的shell取决于用户配置,在/etc/passwd的最后一个字段列出了用户的默认shell,一般为/bin/bash,其他还有zsh,tcsh,dash,csh等。bash shell程序位于/bin目录下,使用长列表可以看出它是一个可执行程序:另外一个默认的shell是/bin/s…...
2024/4/24 14:13:53 - jenkins
1. jenkins持续集成 1.1 jenkins简介 Jenkins是开源CI&CD软件领导者, 提供超过1000个插件来支持构建、部署、自动化, 满足任何项目的需要。 Jenkins用Java语言编写,可在Tomcat等流行的servlet容器中运行,也可独立运行。 CI(Continuous integration持续集成)持续集成强…...
2024/5/1 11:34:33 - Codeup——587 | 问题 B: 反序数
题目描述 设N是一个四位数,它的9倍恰好是其反序数(例如:1234的反序数是4321) 求N的值 输入 程序无任何输入数据。 输出 输出题目要求的四位数,如果结果有多组,则每组结果之间以回车隔开。 思路:直接暴力解决吧…… #include <iostream> #include <cstdio> #…...
2024/4/25 21:10:39 - 剑指offer-41-和为S的两个数字--和为S的连续整数序列
题目一 输入一个递增排序的数组和一个数字S,在数组中查找两个数,使得他们的和是S,输出任意一对即可。看到这个问题我们可以想到的最简单的方法先固定一个数字,然后依次和n - 1个数字判断是不是和为S,但是这样时间复杂度比较高为O(n^2)。可以使用下面这种方法来解决来解决。…...
2024/5/2 15:05:25
最新文章
- 【介绍下Apache的安装与目录结构】
🎥博主:程序员不想YY啊 💫CSDN优质创作者,CSDN实力新星,CSDN博客专家 🤗点赞🎈收藏⭐再看💫养成习惯 ✨希望本文对您有所裨益,如有不足之处,欢迎在评论区提出…...
2024/5/3 12:46:48 - 梯度消失和梯度爆炸的一些处理方法
在这里是记录一下梯度消失或梯度爆炸的一些处理技巧。全当学习总结了如有错误还请留言,在此感激不尽。 权重和梯度的更新公式如下: w w − η ⋅ ∇ w w w - \eta \cdot \nabla w ww−η⋅∇w 个人通俗的理解梯度消失就是网络模型在反向求导的时候出…...
2024/3/20 10:50:27 - 如何转行成为产品经理?
转行NPDP也是很合适的一条发展路径,之后从事新产品开发相关工作~ 一、什么是NPDP? NPDP 是产品经理国际资格认证,美国产品开发与管理协会(PDMA)发起的,是目前国际公认的唯一的新产品开发专业认证ÿ…...
2024/5/1 13:02:24 - Oracle 正则表达式
一、Oracle 正则表达式相关函数 (1) regexp_like :同 like 功能相似(模糊 匹配) (2) regexp_instr :同 instr 功能相似(返回字符所在 下标) (3) regexp_substr : 同 substr 功能相似&…...
2024/5/1 13:21:14 - 【外汇早评】美通胀数据走低,美元调整
原标题:【外汇早评】美通胀数据走低,美元调整昨日美国方面公布了新一期的核心PCE物价指数数据,同比增长1.6%,低于前值和预期值的1.7%,距离美联储的通胀目标2%继续走低,通胀压力较低,且此前美国一季度GDP初值中的消费部分下滑明显,因此市场对美联储后续更可能降息的政策…...
2024/5/1 17:30:59 - 【原油贵金属周评】原油多头拥挤,价格调整
原标题:【原油贵金属周评】原油多头拥挤,价格调整本周国际劳动节,我们喜迎四天假期,但是整个金融市场确实流动性充沛,大事频发,各个商品波动剧烈。美国方面,在本周四凌晨公布5月份的利率决议和新闻发布会,维持联邦基金利率在2.25%-2.50%不变,符合市场预期。同时美联储…...
2024/5/2 16:16:39 - 【外汇周评】靓丽非农不及疲软通胀影响
原标题:【外汇周评】靓丽非农不及疲软通胀影响在刚结束的周五,美国方面公布了新一期的非农就业数据,大幅好于前值和预期,新增就业重新回到20万以上。具体数据: 美国4月非农就业人口变动 26.3万人,预期 19万人,前值 19.6万人。 美国4月失业率 3.6%,预期 3.8%,前值 3…...
2024/4/29 2:29:43 - 【原油贵金属早评】库存继续增加,油价收跌
原标题:【原油贵金属早评】库存继续增加,油价收跌周三清晨公布美国当周API原油库存数据,上周原油库存增加281万桶至4.692亿桶,增幅超过预期的74.4万桶。且有消息人士称,沙特阿美据悉将于6月向亚洲炼油厂额外出售更多原油,印度炼油商预计将每日获得至多20万桶的额外原油供…...
2024/5/2 9:28:15 - 【外汇早评】日本央行会议纪要不改日元强势
原标题:【外汇早评】日本央行会议纪要不改日元强势近两日日元大幅走强与近期市场风险情绪上升,避险资金回流日元有关,也与前一段时间的美日贸易谈判给日本缓冲期,日本方面对汇率问题也避免继续贬值有关。虽然今日早间日本央行公布的利率会议纪要仍然是支持宽松政策,但这符…...
2024/4/27 17:58:04 - 【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响
原标题:【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响近日伊朗局势升温,导致市场担忧影响原油供给,油价试图反弹。此时OPEC表态稳定市场。据消息人士透露,沙特6月石油出口料将低于700万桶/日,沙特已经收到石油消费国提出的6月份扩大出口的“适度要求”,沙特将满…...
2024/4/27 14:22:49 - 【外汇早评】美欲与伊朗重谈协议
原标题:【外汇早评】美欲与伊朗重谈协议美国对伊朗的制裁遭到伊朗的抗议,昨日伊朗方面提出将部分退出伊核协议。而此行为又遭到欧洲方面对伊朗的谴责和警告,伊朗外长昨日回应称,欧洲国家履行它们的义务,伊核协议就能保证存续。据传闻伊朗的导弹已经对准了以色列和美国的航…...
2024/4/28 1:28:33 - 【原油贵金属早评】波动率飙升,市场情绪动荡
原标题:【原油贵金属早评】波动率飙升,市场情绪动荡因中美贸易谈判不安情绪影响,金融市场各资产品种出现明显的波动。随着美国与中方开启第十一轮谈判之际,美国按照既定计划向中国2000亿商品征收25%的关税,市场情绪有所平复,已经开始接受这一事实。虽然波动率-恐慌指数VI…...
2024/4/30 9:43:09 - 【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试
原标题:【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试美国和伊朗的局势继续升温,市场风险情绪上升,避险黄金有向上突破阻力的迹象。原油方面稍显平稳,近期美国和OPEC加大供给及市场需求回落的影响,伊朗局势并未推升油价走强。近期中美贸易谈判摩擦再度升级,美国对中…...
2024/4/27 17:59:30 - 【原油贵金属早评】市场情绪继续恶化,黄金上破
原标题:【原油贵金属早评】市场情绪继续恶化,黄金上破周初中国针对于美国加征关税的进行的反制措施引发市场情绪的大幅波动,人民币汇率出现大幅的贬值动能,金融市场受到非常明显的冲击。尤其是波动率起来之后,对于股市的表现尤其不安。隔夜美国股市出现明显的下行走势,这…...
2024/5/2 15:04:34 - 【外汇早评】美伊僵持,风险情绪继续升温
原标题:【外汇早评】美伊僵持,风险情绪继续升温昨日沙特两艘油轮再次发生爆炸事件,导致波斯湾局势进一步恶化,市场担忧美伊可能会出现摩擦生火,避险品种获得支撑,黄金和日元大幅走强。美指受中美贸易问题影响而在低位震荡。继5月12日,四艘商船在阿联酋领海附近的阿曼湾、…...
2024/4/28 1:34:08 - 【原油贵金属早评】贸易冲突导致需求低迷,油价弱势
原标题:【原油贵金属早评】贸易冲突导致需求低迷,油价弱势近日虽然伊朗局势升温,中东地区几起油船被袭击事件影响,但油价并未走高,而是出于调整结构中。由于市场预期局势失控的可能性较低,而中美贸易问题导致的全球经济衰退风险更大,需求会持续低迷,因此油价调整压力较…...
2024/4/26 19:03:37 - 氧生福地 玩美北湖(上)——为时光守候两千年
原标题:氧生福地 玩美北湖(上)——为时光守候两千年一次说走就走的旅行,只有一张高铁票的距离~ 所以,湖南郴州,我来了~ 从广州南站出发,一个半小时就到达郴州西站了。在动车上,同时改票的南风兄和我居然被分到了一个车厢,所以一路非常愉快地聊了过来。 挺好,最起…...
2024/4/29 20:46:55 - 氧生福地 玩美北湖(中)——永春梯田里的美与鲜
原标题:氧生福地 玩美北湖(中)——永春梯田里的美与鲜一觉醒来,因为大家太爱“美”照,在柳毅山庄去寻找龙女而错过了早餐时间。近十点,向导坏坏还是带着饥肠辘辘的我们去吃郴州最富有盛名的“鱼头粉”。说这是“十二分推荐”,到郴州必吃的美食之一。 哇塞!那个味美香甜…...
2024/4/30 22:21:04 - 氧生福地 玩美北湖(下)——奔跑吧骚年!
原标题:氧生福地 玩美北湖(下)——奔跑吧骚年!让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 啊……啊……啊 两…...
2024/5/1 4:32:01 - 扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!
原标题:扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!扒开伪装医用面膜,翻六倍价格宰客!当行业里的某一品项火爆了,就会有很多商家蹭热度,装逼忽悠,最近火爆朋友圈的医用面膜,被沾上了污点,到底怎么回事呢? “比普通面膜安全、效果好!痘痘、痘印、敏感肌都能用…...
2024/4/27 23:24:42 - 「发现」铁皮石斛仙草之神奇功效用于医用面膜
原标题:「发现」铁皮石斛仙草之神奇功效用于医用面膜丽彦妆铁皮石斛医用面膜|石斛多糖无菌修护补水贴19大优势: 1、铁皮石斛:自唐宋以来,一直被列为皇室贡品,铁皮石斛生于海拔1600米的悬崖峭壁之上,繁殖力差,产量极低,所以古代仅供皇室、贵族享用 2、铁皮石斛自古民间…...
2024/4/28 5:48:52 - 丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者
原标题:丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者【公司简介】 广州华彬企业隶属香港华彬集团有限公司,专注美业21年,其旗下品牌: 「圣茵美」私密荷尔蒙抗衰,产后修复 「圣仪轩」私密荷尔蒙抗衰,产后修复 「花茵莳」私密荷尔蒙抗衰,产后修复 「丽彦妆」专注医学护…...
2024/4/30 9:42:22 - 广州械字号面膜生产厂家OEM/ODM4项须知!
原标题:广州械字号面膜生产厂家OEM/ODM4项须知!广州械字号面膜生产厂家OEM/ODM流程及注意事项解读: 械字号医用面膜,其实在我国并没有严格的定义,通常我们说的医美面膜指的应该是一种「医用敷料」,也就是说,医用面膜其实算作「医疗器械」的一种,又称「医用冷敷贴」。 …...
2024/5/2 9:07:46 - 械字号医用眼膜缓解用眼过度到底有无作用?
原标题:械字号医用眼膜缓解用眼过度到底有无作用?医用眼膜/械字号眼膜/医用冷敷眼贴 凝胶层为亲水高分子材料,含70%以上的水分。体表皮肤温度传导到本产品的凝胶层,热量被凝胶内水分子吸收,通过水分的蒸发带走大量的热量,可迅速地降低体表皮肤局部温度,减轻局部皮肤的灼…...
2024/4/30 9:42:49 - 配置失败还原请勿关闭计算机,电脑开机屏幕上面显示,配置失败还原更改 请勿关闭计算机 开不了机 这个问题怎么办...
解析如下:1、长按电脑电源键直至关机,然后再按一次电源健重启电脑,按F8健进入安全模式2、安全模式下进入Windows系统桌面后,按住“winR”打开运行窗口,输入“services.msc”打开服务设置3、在服务界面,选中…...
2022/11/19 21:17:18 - 错误使用 reshape要执行 RESHAPE,请勿更改元素数目。
%读入6幅图像(每一幅图像的大小是564*564) f1 imread(WashingtonDC_Band1_564.tif); subplot(3,2,1),imshow(f1); f2 imread(WashingtonDC_Band2_564.tif); subplot(3,2,2),imshow(f2); f3 imread(WashingtonDC_Band3_564.tif); subplot(3,2,3),imsho…...
2022/11/19 21:17:16 - 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机...
win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”问题的解决方法在win7系统关机时如果有升级系统的或者其他需要会直接进入一个 等待界面,在等待界面中我们需要等待操作结束才能关机,虽然这比较麻烦,但是对系统进行配置和升级…...
2022/11/19 21:17:15 - 台式电脑显示配置100%请勿关闭计算机,“准备配置windows 请勿关闭计算机”的解决方法...
有不少用户在重装Win7系统或更新系统后会遇到“准备配置windows,请勿关闭计算机”的提示,要过很久才能进入系统,有的用户甚至几个小时也无法进入,下面就教大家这个问题的解决方法。第一种方法:我们首先在左下角的“开始…...
2022/11/19 21:17:14 - win7 正在配置 请勿关闭计算机,怎么办Win7开机显示正在配置Windows Update请勿关机...
置信有很多用户都跟小编一样遇到过这样的问题,电脑时发现开机屏幕显现“正在配置Windows Update,请勿关机”(如下图所示),而且还需求等大约5分钟才干进入系统。这是怎样回事呢?一切都是正常操作的,为什么开时机呈现“正…...
2022/11/19 21:17:13 - 准备配置windows 请勿关闭计算机 蓝屏,Win7开机总是出现提示“配置Windows请勿关机”...
Win7系统开机启动时总是出现“配置Windows请勿关机”的提示,没过几秒后电脑自动重启,每次开机都这样无法进入系统,此时碰到这种现象的用户就可以使用以下5种方法解决问题。方法一:开机按下F8,在出现的Windows高级启动选…...
2022/11/19 21:17:12 - 准备windows请勿关闭计算机要多久,windows10系统提示正在准备windows请勿关闭计算机怎么办...
有不少windows10系统用户反映说碰到这样一个情况,就是电脑提示正在准备windows请勿关闭计算机,碰到这样的问题该怎么解决呢,现在小编就给大家分享一下windows10系统提示正在准备windows请勿关闭计算机的具体第一种方法:1、2、依次…...
2022/11/19 21:17:11 - 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”的解决方法...
今天和大家分享一下win7系统重装了Win7旗舰版系统后,每次关机的时候桌面上都会显示一个“配置Windows Update的界面,提示请勿关闭计算机”,每次停留好几分钟才能正常关机,导致什么情况引起的呢?出现配置Windows Update…...
2022/11/19 21:17:10 - 电脑桌面一直是清理请关闭计算机,windows7一直卡在清理 请勿关闭计算机-win7清理请勿关机,win7配置更新35%不动...
只能是等着,别无他法。说是卡着如果你看硬盘灯应该在读写。如果从 Win 10 无法正常回滚,只能是考虑备份数据后重装系统了。解决来方案一:管理员运行cmd:net stop WuAuServcd %windir%ren SoftwareDistribution SDoldnet start WuA…...
2022/11/19 21:17:09 - 计算机配置更新不起,电脑提示“配置Windows Update请勿关闭计算机”怎么办?
原标题:电脑提示“配置Windows Update请勿关闭计算机”怎么办?win7系统中在开机与关闭的时候总是显示“配置windows update请勿关闭计算机”相信有不少朋友都曾遇到过一次两次还能忍但经常遇到就叫人感到心烦了遇到这种问题怎么办呢?一般的方…...
2022/11/19 21:17:08 - 计算机正在配置无法关机,关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机...
关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!关机提示 windows7 正在配…...
2022/11/19 21:17:05 - 钉钉提示请勿通过开发者调试模式_钉钉请勿通过开发者调试模式是真的吗好不好用...
钉钉请勿通过开发者调试模式是真的吗好不好用 更新时间:2020-04-20 22:24:19 浏览次数:729次 区域: 南阳 > 卧龙 列举网提醒您:为保障您的权益,请不要提前支付任何费用! 虚拟位置外设器!!轨迹模拟&虚拟位置外设神器 专业用于:钉钉,外勤365,红圈通,企业微信和…...
2022/11/19 21:17:05 - 配置失败还原请勿关闭计算机怎么办,win7系统出现“配置windows update失败 还原更改 请勿关闭计算机”,长时间没反应,无法进入系统的解决方案...
前几天班里有位学生电脑(windows 7系统)出问题了,具体表现是开机时一直停留在“配置windows update失败 还原更改 请勿关闭计算机”这个界面,长时间没反应,无法进入系统。这个问题原来帮其他同学也解决过,网上搜了不少资料&#x…...
2022/11/19 21:17:04 - 一个电脑无法关闭计算机你应该怎么办,电脑显示“清理请勿关闭计算机”怎么办?...
本文为你提供了3个有效解决电脑显示“清理请勿关闭计算机”问题的方法,并在最后教给你1种保护系统安全的好方法,一起来看看!电脑出现“清理请勿关闭计算机”在Windows 7(SP1)和Windows Server 2008 R2 SP1中,添加了1个新功能在“磁…...
2022/11/19 21:17:03 - 请勿关闭计算机还原更改要多久,电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机怎么办...
许多用户在长期不使用电脑的时候,开启电脑发现电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机。。.这要怎么办呢?下面小编就带着大家一起看看吧!如果能够正常进入系统,建议您暂时移…...
2022/11/19 21:17:02 - 还原更改请勿关闭计算机 要多久,配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以...
配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!配置windows update失败 还原更改 请勿关闭计算机&#x…...
2022/11/19 21:17:01 - 电脑配置中请勿关闭计算机怎么办,准备配置windows请勿关闭计算机一直显示怎么办【图解】...
不知道大家有没有遇到过这样的一个问题,就是我们的win7系统在关机的时候,总是喜欢显示“准备配置windows,请勿关机”这样的一个页面,没有什么大碍,但是如果一直等着的话就要两个小时甚至更久都关不了机,非常…...
2022/11/19 21:17:00 - 正在准备配置请勿关闭计算机,正在准备配置windows请勿关闭计算机时间长了解决教程...
当电脑出现正在准备配置windows请勿关闭计算机时,一般是您正对windows进行升级,但是这个要是长时间没有反应,我们不能再傻等下去了。可能是电脑出了别的问题了,来看看教程的说法。正在准备配置windows请勿关闭计算机时间长了方法一…...
2022/11/19 21:16:59 - 配置失败还原请勿关闭计算机,配置Windows Update失败,还原更改请勿关闭计算机...
我们使用电脑的过程中有时会遇到这种情况,当我们打开电脑之后,发现一直停留在一个界面:“配置Windows Update失败,还原更改请勿关闭计算机”,等了许久还是无法进入系统。如果我们遇到此类问题应该如何解决呢࿰…...
2022/11/19 21:16:58 - 如何在iPhone上关闭“请勿打扰”
Apple’s “Do Not Disturb While Driving” is a potentially lifesaving iPhone feature, but it doesn’t always turn on automatically at the appropriate time. For example, you might be a passenger in a moving car, but your iPhone may think you’re the one dri…...
2022/11/19 21:16:57