当前位置: 首页 > news >正文

面试:C++ 11 智能指针

查询内存泄露方法

啥是内存泄露

内存泄露在维基百科中的解释如下:

在计算机科学中,内存泄漏指由于疏忽或错误造成程序未能释放已经不再使用的内存。内存泄漏并非指内存在物理上的消失,而是应用程序分配某段内存后,由于设计错误,导致在释放该段内存之前就失去了对该段内存的控制,从而造成了内存的浪费。

在C++中出现内存泄露的主要原因就是程序猿在申请了内存后(malloc(), new),没有及时释放没用的内存空间,甚至消灭了指针导致该区域内存空间根本无法释放。

知道了出现内存泄露的原因就能知道如何应对内存泄露,即:不用了的内存空间记得释放,不释放留着过年哇!

内存泄漏可能会导致严重的后果:

  • 程序运行后,随着时间占用了更多的内存,最后无内存可用而崩溃;
  • 程序消耗了大量的内存,导致其他程序无法正常使用;
  • 程序消耗了大量内存,导致消费者选用了别人的程序而不是你的;
  • 经常做出内存泄露bug的程序猿被公司开出而贫困潦倒。

如何知道自己的程序存在内存泄露?

根据内存泄露的原因及其恶劣的后果,我们可以通过其主要表现来发现程序是否存在内存泄漏:程序长时间运行后内存占用率一直不断的缓慢的上升,而实际上在你的逻辑中并没有这么多的内存需求。

如何定位到泄露点呢?

  1. 根据原理,我们可以先review自己的代码,利用"查找"功能,查询newdelete,看看内存的申请与释放是不是成对释放的,这使你迅速发现一些逻辑较为简单的内存泄露情况。
  2. 如果依旧发生内存泄露,可以通过记录申请与释放的对象数目是否一致来判断。在类中追加一个静态变量 static int count;在构造函数中执行count++;在析构函数中执行count--;,通过在程序结束前将所有类析构,之后输出静态变量,看count的值是否为0,如果为0,则问题并非出现在该处,如果不为0,则是该类型对象没有完全释放。
  3. 检查类中申请的空间是否完全释放,尤其是存在继承父类的情况,看看子类中是否调用了父类的析构函数,有可能会因为子类析构时没有是否父类中申请的内存空间。
  4. 对于函数中申请的临时空间,认真检查,是否存在提前跳出函数的地方没有释放内存。

【如何优雅地检测内存泄漏?5种内存泄漏的检测及定位工具重新理解内存】

(C++后台开发)如何优雅地检测内存泄漏?5种内存泄漏的检测及定位工具重新理解内存_哔哩哔哩_bilibili​www.bilibili.com/video/BV1Fs4y177ht/?share_source=copy_web&vd_source=64f9e03b735a65ecab46f345348e1993​编辑

STL 的智能指针

为了减少出现内存泄露的情况,STL中使用智能指针来减少泄露。STL中一般有四种智能指针:

指针类别支持备注
unique_ptrC++ 11拥有独有对象所有权语义的智能指针
shared_ptrC++ 11拥有共享对象所有权语义的智能指针
weak_ptrC++ 11到 std::shared_ptr 所管理对象的弱引用
auto_ptrC++ 17中移除拥有严格对象所有权语义的智能指针

因为 auto_ptr 已经在 C++ 17 中移除,对于面向未来的程序员来说,最好减少在代码中出现该使用的频次吧,这里我便不再研究该类型。又因为weak_ptrshared_ptr的弱引用,所以,主要的只能指针分为两个unique_ptrshared_ptr

std::unique_ptr 是通过指针占有并管理另一对象,并在 unique_ptr 离开作用域时释放该对象的智能指针。在下列两者之一发生时用关联的删除器释放对象:

  • 销毁了管理的 unique_ptr 对象
  • 通过 operator= 或 reset() 赋值另一指针给管理的 unique_ptr 对象。

std::shared_ptr 是通过指针保持对象共享所有权的智能指针。多个 shared_ptr 对象可占有同一对象。下列情况之一出现时销毁对象并解分配其内存:

  • 最后剩下的占有对象的 shared_ptr 被销毁;
  • 最后剩下的占有对象的 shared_ptr 被通过 operator= 或 reset() 赋值为另一指针。

unique_ptr

这是个独占式的指针对象,在任何时间、资源只能被一个指针占有,当unique_ptr离开作用域,指针所包含的内容会被释放。

创建

unique_ptr<int> uptr( new int );
unique_ptr<int[ ]> uptr( new int[5] );
​
//声明,可以用一个指针显示的初始化,或者声明成一个空指针,可以指向一个类型为T的对象
shared_ptr<T> sp;
unique_ptr<T> up;
//赋值,返回相对应类型的智能指针,指向一个动态分配的T类型对象,并且用args来初始化这个对象
make_shared<T>(args);
make_unique<T>(args);     //注意make_unique是C++14之后才有的
//用来做条件判断,如果其指向一个对象,则返回true否则返回false
p;
//解引用
*p;
//获得其保存的指针,一般不要用
p.get();
//交换指针
swap(p,q);
p.swap(q);
​
//release()用法//release()返回原来智能指针指向的指针,只负责转移控制权,不负责释放内存,常见的用法unique_ptr<int> q(p.release()) // 此时p失去了原来的的控制权交由q,同时p指向nullptr  //所以如果单独用:p.release()//则会导致p丢了控制权的同时,原来的内存得不到释放//则会导致//reset()用法p.reset()     // 释放p原来的对象,并将其置为nullptr,p = nullptr   // 等同于上面一步p.reset(q)    // 注意此处q为一个内置指针,令p释放原来的内存,p新指向这个对象

类满足可移动构造 (MoveConstructible) 和可移动赋值 (MoveAssignable) 的要求,但不满足可复制构造 (CopyConstructible) 或可复制赋值 (CopyAssignable) 的要求。 因此不可以使用 = 操作和拷贝构造函数,仅能使用移动操作。

Demo

#include <iostream>
#include <vector>
#include <memory>
#include <cstdio>
#include <fstream>
#include <cassert>
#include <functional>
​
struct B {virtual void bar() { std::cout << "B::bar\n"; }virtual ~B() = default;
};
struct D : B
{D() { std::cout << "D::D\n";  }~D() { std::cout << "D::~D\n";  }void bar() override { std::cout << "D::bar\n";  }
};
​
// 消费 unique_ptr 的函数能以值或以右值引用接收它
std::unique_ptr<D> pass_through(std::unique_ptr<D> p)
{p->bar();return p;
}
​
void close_file(std::FILE* fp) { std::fclose(fp); }
​
int main()
{std::cout << "unique ownership semantics demo\n";{auto p = std::make_unique<D>(); // p 是占有 D 的 unique_ptrauto q = pass_through(std::move(p));assert(!p); // 现在 p 不占有任何内容并保有空指针q->bar();   // 而 q 占有 D 对象} // ~D 调用于此
​std::cout << "Runtime polymorphism demo\n";{std::unique_ptr<B> p = std::make_unique<D>(); // p 是占有 D 的 unique_ptr// 作为指向基类的指针p->bar(); // 虚派发
​std::vector<std::unique_ptr<B>> v;  // unique_ptr 能存储于容器v.push_back(std::make_unique<D>());v.push_back(std::move(p));v.emplace_back(new D);for(auto& p: v) p->bar(); // 虚派发} // ~D called 3 times
​std::cout << "Custom deleter demo\n";std::ofstream("demo.txt") << 'x'; // 准备要读的文件{std::unique_ptr<std::FILE, void (*)(std::FILE*) > fp(std::fopen("demo.txt", "r"),close_file);if(fp) // fopen 可以打开失败;该情况下 fp 保有空指针std::cout << (char)std::fgetc(fp.get()) << '\n';} // fclose() 调用于此,但仅若 FILE* 不是空指针// (即 fopen 成功)
​std::cout << "Custom lambda-expression deleter demo\n";{std::unique_ptr<D, std::function<void(D*)>> p(new D, [](D* ptr){std::cout << "destroying from a custom deleter...\n";delete ptr;});  // p 占有 Dp->bar();} // 调用上述 lambda 并销毁 D
​std::cout << "Array form of unique_ptr demo\n";{std::unique_ptr<D[]> p{new D[3]};} // 调用 ~D 3 次
}

输出结果:

unique ownership semantics demo
D::D
D::bar
D::bar
D::~D
Runtime polymorphism demo
D::D
D::bar
D::D
D::D
D::bar
D::bar
D::bar
D::~D
D::~D
D::~D
Custom deleter demo
x
Custom lambda-expression deleter demo
D::D
D::bar
destroying from a custom deleter...
D::~D
Array form of unique_ptr demo
D::D
D::D
D::D
D::~D
D::~D
D::~D

shared_ptr

有两种方式创建 shared_ptr:使用make_shared宏来加速创建的过程。因为shared_ptr主动分配内存并且保存引用计数(reference count),make_shared 以一种更有效率的方法来实现创建工作。

void main( )
{shared_ptr<int> sptr1( new int );shared_ptr<int> sptr2 = make_shared<int>(100);
}

析构

shared_ptr默认调用delete释放关联的资源。如果用户采用一个不一样的析构策略时,他可以自由指定构造这个shared_ptr的策略。在此场景下,shared_ptr指向一组对象,但是当离开作用域时,默认的析构函数调用delete释放资源。实际上,我们应该调用delete[]来销毁这个数组。用户可以通过调用一个函数,例如一个lamda表达式,来指定一个通用的释放步骤。

void main( )
{shared_ptr<Test> sptr1( new Test[5],[ ](Test* p) { delete[ ] p; } );
}

注意 尽量不要用裸指针创建 shared_ptr,以免出现分组不同导致错误

void main( )
{
// 错误int* p = new int;shared_ptr<int> sptr1( p);   // count 1shared_ptr<int> sptr2( p );  // count 1
​
// 正确shared_ptr<int> sptr1( new int );  // count 1shared_ptr<int> sptr2 = sptr1;     // count 2shared_ptr<int> sptr3;           sptr3 =sptr1                       // count 3
}

循环引用

因为 Shared_ptr 是多个指向的指针,可能出现循环引用,导致超出了作用域后仍有内存未能释放。

class B;
class A
{
public:A(  ) : m_sptrB(nullptr) { };~A( ){cout<<" A is destroyed"<<endl;}shared_ptr<B> m_sptrB;
};
class B
{
public:B(  ) : m_sptrA(nullptr) { };~B( ){cout<<" B is destroyed"<<endl;}shared_ptr<A> m_sptrA;
};
//***********************************************************
void main( )
{shared_ptr<B> sptrB( new B );  // sptB count 1shared_ptr<A> sptrA( new A );  // sptB count 1sptrB->m_sptrA = sptrA;    // sptB count 2sptrA->m_sptrB = sptrB;    // sptA count 2
}
​
// 超出定义域
// sptA count 1
// sptB count 2

demo

#include <iostream>
#include <memory>
#include <thread>
#include <chrono>
#include <mutex>
​
struct Base
{Base() { std::cout << "  Base::Base()\n"; }// 注意:此处非虚析构函数 OK~Base() { std::cout << "  Base::~Base()\n"; }
};
​
struct Derived: public Base
{Derived() { std::cout << "  Derived::Derived()\n"; }~Derived() { std::cout << "  Derived::~Derived()\n"; }
};
​
void thr(std::shared_ptr<Base> p)
{std::this_thread::sleep_for(std::chrono::seconds(1));std::shared_ptr<Base> lp = p; // 线程安全,虽然自增共享的 use_count{static std::mutex io_mutex;std::lock_guard<std::mutex> lk(io_mutex);std::cout << "local pointer in a thread:\n"<< "  lp.get() = " << lp.get()<< ", lp.use_count() = " << lp.use_count() << '\n';}
}
​
int main()
{std::shared_ptr<Base> p = std::make_shared<Derived>();
​std::cout << "Created a shared Derived (as a pointer to Base)\n"<< "  p.get() = " << p.get()<< ", p.use_count() = " << p.use_count() << '\n';std::thread t1(thr, p), t2(thr, p), t3(thr, p);p.reset(); // 从 main 释放所有权std::cout << "Shared ownership between 3 threads and released\n"<< "ownership from main:\n"<< "  p.get() = " << p.get()<< ", p.use_count() = " << p.use_count() << '\n';t1.join(); t2.join(); t3.join();std::cout << "All threads completed, the last one deleted Derived\n";
}

可能的输出结果

Base::Base()Derived::Derived()
Created a shared Derived (as a pointer to Base)p.get() = 0xc99028, p.use_count() = 1
Shared ownership between 3 threads and released
ownership from main:p.get() = (nil), p.use_count() = 0
local pointer in a thread:lp.get() = 0xc99028, lp.use_count() = 3
local pointer in a thread:lp.get() = 0xc99028, lp.use_count() = 4
local pointer in a thread:lp.get() = 0xc99028, lp.use_count() = 2Derived::~Derived()Base::~Base()
All threads completed, the last one deleted Derived

weak_ptr

std::weak_ptr 是一种智能指针,它对被 std::shared_ptr 管理的对象存在非拥有性(“弱”)引用。在访问所引用的对象前必须先转换为 std::shared_ptr。

std::weak_ptr 用来表达临时所有权的概念:当某个对象只有存在时才需要被访问,而且随时可能被他人删除时,可以使用 std::weak_ptr 来跟踪该对象。需要获得临时所有权时,则将其转换为 std::shared_ptr,此时如果原来的 std::shared_ptr 被销毁,则该对象的生命期将被延长至这个临时的 std::shared_ptr 同样被销毁为止。

std::weak_ptr 的另一用法是打断 std::shared_ptr 所管理的对象组成的环状引用。若这种环被孤立(例如无指向环中的外部共享指针),则 shared_ptr 引用计数无法抵达零,而内存被泄露。能令环中的指针之一为弱指针以避免此情况。

创建

void main( )
{shared_ptr<Test> sptr( new Test );   // 强引用 1weak_ptr<Test> wptr( sptr );         // 强引用 1 弱引用 1weak_ptr<Test> wptr1 = wptr;         // 强引用 1 弱引用 2
}

将一个weak_ptr赋给另一个weak_ptr会增加弱引用计数(weak reference count)。 所以,当shared_ptr离开作用域时,其内的资源释放了,这时候指向该shared_ptr的weak_ptr发生了什么?weak_ptr过期了(expired)。如何判断weak_ptr是否指向有效资源,有两种方法:

  • 调用use-count()去获取引用计数,该方法只返回强引用计数,并不返回弱引用计数。
  • 调用expired()方法。比调用use_count()方法速度更快。

从weak_ptr调用lock()可以得到shared_ptr或者直接将weak_ptr转型为shared_ptr

解决 shared_ptr 循环引用问题

class B;
class A
{
public:A(  ) : m_a(5)  { };~A( ){cout<<" A is destroyed"<<endl;}void PrintSpB( );weak_ptr<B> m_sptrB;int m_a;
};
class B
{
public:B(  ) : m_b(10) { };~B( ){cout<<" B is destroyed"<<endl;}weak_ptr<A> m_sptrA;int m_b;
};
​
void A::PrintSpB( )
{if( !m_sptrB.expired() ){  cout<< m_sptrB.lock( )->m_b<<endl;}
}
​
void main( )
{shared_ptr<B> sptrB( new B );shared_ptr<A> sptrA( new A );sptrB->m_sptrA = sptrA;sptrA->m_sptrB = sptrB;sptrA->PrintSpB( );
}

STL 智能指针的陷阱/不够智能的地方

  1. 尽量用make_shared/make_unique,少用new
std::shared_ptr在实现的时候使用的refcount技术,因此内部会有一个计数器(控制块,用来管理数据)和一个指针,指向数据。因此在执行 std::shared_ptr<A> p2(new A) 的时候,首先会申请数据的内存,然后申请内控制块,因此是两次内存申请,而 std::make_shared<A>()则是只执行一次内存申请,将数据和控制块的申请放到一起。
  1. 不要使用相同的内置指针来初始化(或者reset)多个智能指针
  2. 不要delete get()返回的指针
  3. 不要用get()初始化/reset另一个智能指针
  4. 智能指针管理的资源它只会默认删除new分配的内存,如果不是new分配的则要传递给其一个删除器
  5. 不要把this指针交给智能指针管理
    以下代码发生了什么事情呢?还是同样的错误。把原生指针 this 同时交付给了 m_sp 和 p 管理,这样会导致 this 指针被 delete 两次。 这里值得注意的是:以上所说的交付给m_sp 和 p 管理不对,并不是指不能多个shared_ptr同时占有同一类资源。shared_ptr之间的资源共享是通过shared_ptr智能指针拷贝、赋值实现的,因为这样可以引起计数器的更新;而如果直接通过原生指针来初始化,就会导致m_sp和p都根本不知道对方的存在,然而却两者都管理同一块地方。相当于”一间庙里请了两尊神”。
    class Test{
    public:
    void Do(){ m_sp = shared_ptr<Test>(this); }
    private:
    shared_ptr<Test> m_sp;
    };
    int main()
    {
    Test* t = new Test;
    shared_ptr<Test> p(t);
    p->Do();
    return 0;
    }
  6. 不要把一个原生指针给多个shared_ptr或者unique_ptr管理
我们知道,在使用原生指针对智能指针初始化的时候,智能指针对象都视原生指针为自己管理的资源。换句话意思就说:初始化多个智能指针之后,这些智能指针都担负起释放内存的作用。那么就会导致该原生指针会被释放多次!!
int* ptr = new int;
shared_ptr<int> p1(ptr);
shared_ptr<int> p2(ptr);
//p1,p2析构的时候都会释放ptr,同一内存被释放多次!
  1. 不是使用new出来的空间要自定义删除器
以下代码试图将malloc产生的动态内存交给shared_ptr管理;显然是有问题的,delete 和 malloc 牛头不对马嘴!!! 所以我们需要自定义删除器{ free(p); }传递给shared_ptr。
    int main()
{int* pi = (int*)malloc(4 * sizeof(int));shared_ptr<int> sp(pi);return 0;
}
  1. 尽量不要使用 get()
智能指针设计者之处提供get()接口是为了使得智能指针也能够适配原生指针使用的相关函数。这个设计可以说是个好的设计,也可以说是个失败的设计。因为根据封装的封闭原则,我们将原生指针交付给智能指针管理,我们就不应该也不能得到原生指针了;因为原生指针唯一的管理者就应该是智能指针。而不是客户逻辑区的其他什么代码。 所以我们在使用get()的时候要额外小心,禁止使用get()返回的原生指针再去初始化其他智能指针或者释放。(只能够被使用,不能够被管理)。而下面这段代码就违反了这个规定:
int main()
{shared_ptr<int> sp(new int(4));shared_ptr<int> pp(sp.get());return 0;
}

https://zhuanlan.zhihu.com/p/650440110

相关文章:

面试:C++ 11 智能指针

查询内存泄露方法 啥是内存泄露 内存泄露在维基百科中的解释如下&#xff1a; 在计算机科学中&#xff0c;内存泄漏指由于疏忽或错误造成程序未能释放已经不再使用的内存。内存泄漏并非指内存在物理上的消失&#xff0c;而是应用程序分配某段内存后&#xff0c;由于设计错误&…...

设计模式——3. 抽象工厂模式

1. 说明 抽象工厂模式(Abstract Factory Pattern)是一种创建型设计模式,它提供了一种创建一组相关或依赖对象的方式,而无需指定它们的具体类。抽象工厂模式是工厂模式的扩展,它关注于创建一组相关的对象家族,而不仅仅是一个单一的对象。 抽象工厂模式通常涉及以下几个角…...

vscode 无法使用 compilerPath“D:.../bin/arm-none-eabi-g++.exe”解析配置。

最近在使用vscode搭建ODrive STM32开发环境,依次安装了以下内容: 1.Python3: 用于运行工程构建脚本 2.ST-Link/V2 Drivers: STLink/v2编程器的驱动 3.Visual Studio Code: 轻量级但功能强大的源代码编辑器 …...

Vue.js入门模板语法[上] 及Vue.js实现购物车---详细讲解

前言 前面我们学习了Vue的基础入门&#xff0c;接下来我们学习有关Vue的模板语法&#xff0c;学习Vue语法能提高我们的前端开发效率 Vue.js 使用了基于 HTML 的模板语法&#xff0c;允许开发者声明式地将 DOM 绑定至底层 Vue 实例的数据。所有 Vue.js 的模板都是合法的 HTML &a…...

windows下gvim的配置

一、vim配置文件 "查看自己的vimrc所在的目录 "在命令模式下 :echo $MYVIMRC"打开自己的vimrc文件 "在命令模式下 :e $MYVIMRC 二、排版 "查看自己当前的字体及大小 "在命令模式下 :set guifont?"设置默认的字体为仿宋_GB2312&#xff…...

基于复旦微的FMQL45T900全国产化ARM开发开发套件(核心板+底板)

TES745D是我司自主研制的一款基于上海复旦微电子FMQL45T900的全国产化ARM核心板&#xff08;模块&#xff09;。该核心板将复旦微的FMQL45T900&#xff08;与XILINX的XC7Z045-2FFG900I兼容&#xff09;的最小系统集成在了一个87*117mm的核心板上&#xff0c;可以作为一个核心模…...

Leetcode Top100(23)环形链表

给你一个链表的头节点 head &#xff0c;判断链表中是否有环。 如果链表中有某个节点&#xff0c;可以通过连续跟踪 next 指针再次到达&#xff0c;则链表中存在环。 为了表示给定链表中的环&#xff0c;评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置&#xff08;索…...

线性代数基础-行列式

一、行列式之前的概念 1.全排列&#xff1a; 把n个不同的元素排成一列&#xff0c;称为n个元素的全排列&#xff0c;简称排列 &#xff08;实际上就是我们所说的排列组合&#xff0c;符号是A&#xff0c;arrange&#xff09; 2.标准序列&#xff1a; 前一项均小于后一项的序列…...

RT-Thread(学习)

RT-Thread是一款完全由国内团队开发维护的嵌入式实时操作系统&#xff08;RTOS&#xff09;&#xff0c;具有完全的自主知识产权。经过16个年头的沉淀&#xff0c;伴随着物联网的兴起&#xff0c;它正演变成一个功能强大、组件丰富的物联网操作系统。 RT-Thread概述 RT-Threa…...

【MySQL】 MySQL 死锁问题分析优化器特性及优化方案

MySQL 死锁问题分析优化器特性及解决方案 MySQL 锁机制介绍 1、MySQL常用存储引擎的锁机制 MyISAM和MEMORY采用表级锁(table-level locking) BDB采用页面锁(page-level locking)或表级锁&#xff0c;默认为页面锁 InnoDB支持行级锁(row-level locking)和表级锁,默认为行级…...

【C++面向对象侯捷】8.栈,堆和内存管理

文章目录 栈&#xff0c;堆stack object的生命周期static local object的生命周期global object的生命周期heap objects 的生命期new&#xff1a;先分配memory&#xff0c;再调用构造函数delete: 先调用析构函数&#xff0c;再释放 memory动态分配所得的内存块&#xff0c;in V…...

在比特币上使用可检索性证明支付存储费用

我们为用户开发了一种为云存储付费的新方法。 与亚马逊的 S3 等传统云存储相比&#xff0c;用户不必信任服务器。 我们使用比特币智能合约来确保支付取决于服务器的可检索性证明 (PoR)&#xff0c;该证明只能在数据仍然可用且需要时可以检索的情况下生成。 可检索性证明 (PoR)…...

使用SSE(Server-Sent Events)实现服务端给客户端发消息

首先是客户端&#xff0c;看着比较简单。但实际应用中可能要比这复杂&#xff0c;因为默认sse只支持get请求&#xff0c;而且没法携带header。所以如果默认的方法达不到需求的话可能需要额外实现&#xff0c;当然也可以引用第三方库&#xff0c;比如rangermauve/fetch-event-so…...

【Redis】使用rpm包安装redis

背景说明 公司环境处于内网&#xff0c;某同事需要安装redis&#xff0c;如果使用通过源码编译安装redis&#xff0c;很多编译工具如gcc就需要先安装&#xff0c;但处于内网安装起来不太方便&#xff0c;当然也不是不可以。我们此处就选用通过redis的rpm包进行安装。 rpm包查…...

论文阅读-Group-based Fraud Detection Network on e-Commerce Platforms

目录 摘要 1 Introduction 2 BACKGROUND AND RELATED WORK 2.1 Preliminaries 2.2 Related Works 3 MODEL 3.1 Structural Feature Initialization 3.2 Fraudster Community Detection 3.3 Training Objective 4 EXPERIMENT 4.1 Experimental Setup 4.2 Prediction …...

java程序启动时指定JVM内存参数和Xms、Xmx参数学习

先找个java程序来试验&#xff1b;找这个&#xff0c; java实现计算机图形学中点画线算法_java 多个点连成一条线 算法-CSDN博客 JVM内存参数中&#xff0c; -Xms&#xff1a;设置堆内存的初始大小&#xff0c;默认为物理内存的1/64&#xff1b; -Xmx&#xff1a;设置堆内存的…...

【C++编程能力提升】

代码随想录训练营Day44 | Leetcode 518、377 一、完全背包问题1、完全背包与01背包的区别 二、518 零钱兑换II三、377 组合总和IV 一、完全背包问题 1、完全背包与01背包的区别 第一&#xff0c;物品的有限与无限&#xff1b; 01背包&#xff1a;物品是有限的。&#xff08;每…...

FlashDuty Changelog 2023-09-21 | 自定义字段和开发者中心

FlashDuty&#xff1a;一站式告警响应平台&#xff0c;前往此地址免费体验&#xff01; 自定义字段 FlashDuty 已支持接入大部分常见的告警系统&#xff0c;我们将推送内容中的大部分信息放到了 Lables 进行展示。尽管如此&#xff0c;我们用户还是会有一些扩展或定制性的需求…...

贪心算法-

代码随想录 什么是贪心 贪心的本质是选择每一阶段的局部最优&#xff0c;从而达到全局最优。 这么说有点抽象&#xff0c;来举一个例子&#xff1a; 例如&#xff0c;有一堆钞票&#xff0c;你可以拿走十张&#xff0c;如果想达到最大的金额&#xff0c;你要怎么拿&#xff…...

漫谈:C语言 C++ 左值、右值、类型转换

编程不是自然语言&#xff0c;编程自有其内在逻辑。 左值引起的BUG 编译器经常给出类似这样的BUG提示&#xff1a; “表达式必须是可修改的左值” “非常量引用的初始值必须是左值” 看一下示例&#xff1a; #include <iostream>void f(int& x) {} int main() {sho…...

前车之鉴,后车之师

问题分类具体解释可能导致的后果解决方法备注主从延迟数据库写后立即读的场景&#xff0c;比如订单落地成功抛消息&#xff0c;消息接收方再读订单推订单中心、发触达、落地数据等场景&#xff0c;再读数据时走从库&#xff0c;可能读不到数据。脏数据业务逻辑有问题延迟消费。…...

WEB使用VUE3实现地图导航跳转

我们在用手机查看网页时可以通过传入经纬度去设置目的地然后跳转到对应的地图导航软件&#xff0c;如果没有下载软件则会跳转到下载界面 注意&#xff1a; 高德地图是一定会跳转到一个新网页然后去询问用户是否需要打开软件百度和腾讯地图是直接调用软件的这个方法有缺陷&…...

今天聊一聊高性能系统架构设计是什么样的

Java全能学习面试指南&#xff1a;https://javaxiaobear.cn 今天聊一聊大家常听到的高性能系统架构。 高性能系统架构&#xff0c;主要包括两部分内容&#xff0c;性能测试与性能优化。性能优化又可以细分为硬件优化、中间件优化、架构优化及代码优化&#xff0c;知识架构图如…...

鼠标不动了怎么办?3招解决问题!

“这是怎么回事呢&#xff1f;我的鼠标怎么会用着用着就突然不动了呢&#xff1f;现在有一些比较重要的工作要处理。请问有什么方法可以快速解决这个问题吗&#xff1f;” 随着电脑在我们日常生活和工作中的广泛应用&#xff0c;鼠标是我们操作电脑不可或缺的工具之一。但是&am…...

2023-09-23力扣每日一题

链接&#xff1a; 1993. 树上的操作 题意 **Lock&#xff1a;**指定用户给指定节点 上锁 &#xff0c;上锁后其他用户将无法给同一节点上锁。只有当节点处于未上锁的状态下&#xff0c;才能进行上锁操作。**Unlock&#xff1a;**指定用户给指定节点 解锁 &#xff0c;只有当…...

C#中使用Newtonsoft.Charp实现Json对象序列化与反序列化

场景 C#中使用Newtonsoft.Json实现对Json字符串的解析&#xff1a; C#中使用Newtonsoft.Json实现对Json字符串的解析_霸道流氓气质的博客-CSDN博客 上面讲的对JSON字符串进行解析&#xff0c;实际就是JSON对象的反序列化。 在与第三方进行交互时常需要封装对象&#xff0c;…...

Golang开发--互斥锁和读写锁

互斥锁&#xff08;Mutex&#xff09; 互斥锁&#xff08;Mutex&#xff09;是一种并发控制机制&#xff0c;用于保护共享资源的访问。互斥锁用于确保在任何给定时间只有一个 goroutine&#xff08;Go 语言中的并发执行单元&#xff09;可以访问被保护的共享资源&#xff0c;从…...

Springboot 集成WebSocket作为客户端,含重连接功能,开箱即用

使用演示 public static void main(String[] args) throws Exception{//初始化socket客户端BaseWebSocketClient socketClient BaseWebSocketClient.init("传入链接");//发送消息socketClient.sendMessage("填写需要发送的消息", (receive) -> {//这里…...

java调整字符串

package 字符串练习;public class 调整字符串 {/* 如果调整成功则给提示,返回不成功也给提示调整 例如:abcde -> bcdea -> cdeab 就是把第一个值放到最后的位置上现在是给定两个字符串, 选定其中一个进行调整, (我们想一下,如果调整字符串的长度次,那不就是返回到原来的字…...

2023-9

内核向应用层发送netlink单播消息&#xff1a; nlmsg_unicast -> netlink_unicast -> netlink_sendskb -> __netlink_sendskb -> 把skb链入struct sock 的 sk_receive_queue 链表中&#xff0c;再调用sk->sk_data_ready(sk); -> sock_def_readable -> wak…...

哪里有做php网站免费教程/网站推广沈阳

Hexo更改主题后启动服务器&#xff0c;界面显如下字符: extends includes/layout.pug block content include includes/recent-posts.pug include includes/partial 解决方案: 执行如下命令 npm install --save hexo-renderer-jade hexo-generator-feed hexo-generator-sit…...

站酷官网/seo设置是什么

前言 一次偶然&#xff0c;从朋友那里得到一份“java高分面试指南”&#xff0c;里面涵盖了25个分类的面试题以及详细的解析&#xff1a;JavaOOP、Java集合/泛型、Java中的IO与NIO、Java反射、Java序列化、Java注解、多线程&并发、JVM、Mysql、Redis、Memcached、MongoDB、…...

电脑经销部开具网站建设费/服务营销理论

第193场周赛[1480. 一维数组的动态和](https://leetcode-cn.com/problems/running-sum-of-1d-array/)题目描述1Solution1[1481. 不同整数的最少数目](https://leetcode-cn.com/problems/least-number-of-unique-integers-after-k-removals/)题目描述2Solution2[1482. 制作 m 束…...

做电影网站需要什么服务器/百度推广怎么收费

1、操作系统 操作系统有很多, Centos、Suse、Ubuntu、Debian等等。真正在开发中用到最多的就是Centos&#xff0c;而且老版本的还比较多。为了以后的工作考虑&#xff0c;选择Centos7 作为自己的第一开发环境搭建的操作系统。 2、桌面环境 个人对桌面环境也有过一些了解。大概常…...

想要将网站信息插到文本链接怎么做/如何建站

如果启动前不对Linux内核做任何更改&#xff0c;那么Redis启动会报出警告&#xff0c;共三个&#xff1a;如下图所示第一个警告&#xff1a;The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.意思是…...

字节跳动小程序开发平台/关键词优化是什么意思

动态链接&#xff08;Dynamic Linking&#xff09; 每一个栈帧内部都包含一个指向运行时常量池或该栈帧所属方法的引用。包含这个引用的目的就是为了支持当前方法的代码能够实现动态链接。比如invokedynamic指令在Java源文件被编译成字节码文件中时&#xff0c;所有的变量和方…...