【重学C++】02 脱离指针陷阱:深入浅出 C++ 智能指针

文章首发

【重学C++】02 脱离指针陷阱:深入浅出 C++ 智能指针

前言

大家好,今天是【重学C++】系列的第二讲,我们来聊聊C++的智能指针。

为什么需要智能指针

在上一讲《01 C++如何进行内存资源管理》中,提到了对于堆上的内存资源,需要我们手动分配和释放。管理这些资源是个技术活,一不小心,就会导致内存泄漏。

我们再给两段代码,切身体验下原生指针管理内存的噩梦。

void foo(int n) {
    int* ptr = new int(42);
    ...
    if (n > 5) {
	    return;
    }
    ...
    delete ptr;
}


void other_fn(int* ptr) {
	...
};
void bar() {
    int* ptr = new int(42);
    other_fn(ptr);
    // ptr == ?
}

foo函数中,如果入参n > 5, 则会导致指针ptr的内存未被正确释放,从而导致内存泄漏。

bar函数中,我们将指针ptr传递给了另外一个函数other_fn,我们无法确定other_fn有没有释放ptr内存,如果被释放了,那ptr将成为一个悬空指针,bar在后续还继续访问它,会引发未定义行为,可能导致程序崩溃。

上面由于原生指针使用不当导致的内存泄漏、悬空指针问题都可以通过智能指针来轻松避免。

C++智能指针是一种用于管理动态分配内存的指针类。基于RAII设计理念,通过封装原生指针实现的。可以在资源(原生指针对应的对象)生命周期结束时自动释放内存。

C++标准库中,提供了两种最常见的智能指针类型,分别是std::unique_ptrstd::shared_ptr
接下来我们分别详细展开介绍。

吃独食的unique_ptr

std::unique_ptr 是 C++11 引入的智能指针,用于管理动态分配的内存。每个 std::unique_ptr 实例都拥有对其所包含对象的唯一所有权,并在其生命周期结束时自动释放对象。

创建unique_ptr对象

我们可以std::unique_ptr的构造函数或std::make_unique函数(C++14支持)来创建一个unique_ptr对象,在超出作用域时,会自动释放所管理的对象内存。示例代码如下:

#include <memory>
#include <iostream>
class MyClass {
public:
    MyClass() {
        std::cout << "MyClass constructed" << std::endl;
    }

    ~MyClass() {
        std::cout << "MyClass destroyed" << std::endl;
    }
};
int main() {
	std::unique_ptr<MyClass> ptr1(new MyClass);
	// C++14开始支持std::make_unique
    std::unique_ptr<int> ptr2 = std::make_unique<int>(10);
    return 0;
}

代码输出:

MyClass constructed
MyClass destroyed

访问所管理的对象

我们可以像使用原生指针的方式一样,访问unique_ptr所指向的对象。也可以通过get函数获取到原生指针。

MyClass* naked_ptr = ptr1.get();
std::cout << *ptr2 << std::endl; // 输出 10

释放/重置所管理的对象

使用reset函数可以释放unique_ptr所管理的对象,并将其指针重置为nullptr或指定的新指针。reset`大概实现原理如下

template<class T> 
void unique_ptr<T>::reset(pointer ptr = pointer()) noexcept { 
	// 释放指针指向的对象
	delete ptr_; 
	// 重置指针
	ptr_ = ptr;
}

该函数主要完成两件事:

  1. 释放 std::unique_ptr 所管理的对象,以避免内存泄漏。
  2. std::unique_ptr 重置为nullptr或管理另一个对象。

code show time:

#include <iostream>
#include <memory>

class MyClass {
public:
    MyClass() {
        std::cout << "MyClass constructed" << std::endl;
    }

    ~MyClass() {
        std::cout << "MyClass destroyed" << std::endl;
    }
};

int main() {
    // 创建一个 std::unique_ptr 对象,指向一个 MyClass 对象
    std::unique_ptr<MyClass> ptr(new MyClass);

    // 调用 reset,将 std::unique_ptr 重置为管理另一个 MyClass 对象
    ptr.reset(new MyClass);
    return;
}

移动所有权

一个对象资源只能同时被一个unique_ptr管理。当尝试把一个unique_ptr直接赋值给另外一个unique_ptr会编译报错。

#include <memory>
int main() {
    std::unique_ptr<int> p1 = std::make_unique<int>(42);
    std::unique_ptr<int> p2 = p1; // 编译报错
    return 0;
}

为了把一个 std::unique_ptr 对象的所有权移动到另一个对象中,我们必须配合std::move移动函数。

#include <memory>
#include <iostream>
int main() {
    std::unique_ptr<int> p1 = std::make_unique<int>(42);
    std::unique_ptr<int> p2 = std::move(p1); // ok
    std::cout << *p2 << std::endl; // 42
    std::cout << (p1.get() == nullptr) << std::endl; // true
    return 0;
}

这个例子中, 我们把p1通过std::move将其管理对象的所有权转移给了p2, 此时p2接管了对象,而p1不再拥有管理对象的所有权,即无法再操作到该对象了。

乐于分享的shared_ptr

shared_ptr是C++11提供的另外一种常见的智能指针,与unique_ptr独占对象方式不同,shared_ptr是一种共享式智能指针,允许多个shared_ptr指针共同拥有同一个对象,采用引用计数的方式来管理对象的生命周期。当所有的 shared_ptr 对象都销毁时,才会自动释放所管理的对象。

创建shared_ptr对象

同样的,C++也提供了std::shared_ptr构造函数和std::make_shared函数来创建std::shared_ptr对象。

#include <memory>
int main() {
	std::shared_ptr<int> p1(new int(10));
	std::shared_ptr<int> p2 = std::make_shared<int>(20);
	return;
}

多个shared_ptr共享一个对象

可以通过赋值操作实现多个shared_ptr共享一个资源对象,例如

std::shared_ptr<int>p3 = p2;

shared_ptr采用引用计数的方式管理资源对象的生命周期,通过分配一个额外内存当计数器。

当一个新的shared_ptr被创建时,它对应的计数器被初始化为1。每当赋值给另外一个shared_ptr共享同一个对象时,计数器值会加1。当某个shared_ptr被销毁时,计数值会减1,当计数值变为0时,说明没有任何shared_ptr引用这个对象,会将对象进行回收。
image.png

C++提供了use_count函数来获取std::shared_ptr所管理对象的引用计数,例如

std::cout << "p1 use count: " << p1.use_count() << std::endl;

释放/重置所管理的对象

可以使用reset函数来释放/重置shared_ptr所管理的对象。大概实现原理如下(不考虑并发场景)

void reset(T* ptr = nullptr) {
	if (ref_count != nullptr) { 
		(*ref_count)--;
		if (*ref_count == 0) { 
			delete data; 
			delete ref_count; 
		} 
	} 
	data = ptr; 
	ref_count = (data == nullptr) ? nullptr : new size_t(1); 
}

data指针来存储管理的资源,指针ref_count 来存储计数器的值。

在 reset 方法中,需要减少计数器的值,如果计数器减少后为 0,则需要释放管理的资源,如果减少后不为0,则不会释放之前的资源对象。

如果reset指定了新的资源指针,则需要重新设置 data 和 ref_count,并将计数器初始化为 1。否则,将计数器指针置为nullptr

shared_ptr使用注意事项

避免循环引用

由于 shared_ptr 具有共享同一个资源对象的能力,因此容易出现循环引用的情况。例如:

struct Node { 
	std::shared_ptr<Node> next; 
};

int main() {
	std::shared_ptr<Node> node1(new Node);
	std::shared_ptr<Node> node2(new Node); 
	node1->next = node2; 
	node2->next = node1;
}

在上述代码中,node1node2 互相引用,在析构时会发现计数器的值不为0,不会释放所管理的对象,产生内存泄漏。

为了避免循环引用,可以将其中一个指针改为 weak_ptr 类型。weak_ptr也是一种智能指针,通常配合shared_ptr一起使用。

weak_ptr是一种弱引用,不对所指向的对象进行计数引用,也就是说,不增加所指对象的引用计数。当所有的shared_ptr都析构了,不再指向该资源时,该资源会被销毁,同时对应的所有weak_ptr都会变成nullptr,这时我们就可以利用expired()方法来判断这个weak_ptr是否已经失效。

我们可以通过weak_ptrlock()方法来获得一个指向共享对象的shared_ptr。如果weak_ptr已经失效,lock()方法将返回一个空的shared_ptr

下面是weak_ptr的基本使用示例:

#include <iostream>
#include <memory>

int main() {
    std::shared_ptr<int> sp = std::make_shared<int>(42);
    // 创建shared_ptr对应的weak_ptr指针
    std::weak_ptr<int> wp(sp);

	// 通过lock创建一个对应的shared_ptr
    if (auto p = wp.lock()) {
        std::cout << "shared_ptr value: " << *p << std::endl;
        std::cout << "shared_ptr use_count: " << p.use_count() << std::endl;
    } else {
        std::cout << "wp is expired" << std::endl;
    }

	// 释放shared_ptr指向的资源,此时weak_ptr失效
    sp.reset();
    std::cout << "wp is expired: " <<  wp.expired() << std::endl;
    return 0;
}

代码输出如下

shared_ptr value: 42
shared_ptr use_count: 2
wp is expired: 1

回到shared_ptr的循环引用问题,利用weak_ptr不会增加shared_ptr的引用计数的特点,我们将Node.next的类型改为weak_ptr, 避免node1和node2互相循环引用。修改后代码如下

```cpp
struct Node { 
	std::weak_ptr<Node> next; 
};

int main() {
	std::shared_ptr<Node> node1(new Node);
	std::shared_ptr<Node> node2(new Node); 
	node1->next = std::weak_ptr<Node>(node2); 
	node2->next = std::weak_ptr<Node>(node1); ;
}

避免裸指针与shared_ptr混用

先看看以下代码

int* q = new int(9);
{
	std::shared_ptr<int> p(new int(10));
	...
	q = p.get();
}
std::cout << *q << std::endl;

get函数返回 std::shared_ptr 所持有的指针,但是不会增加引用计数。所以在shared_ptr析构时,将该指针指向的对象给释放掉了,导致指针q变成一个悬空指针。

避免一个原始指针初始化多个shared_ptr

int* p = new int(10);
std::shared_ptr<int> ptr1(p);
// error: 两个shared_ptr指向同一个资源,会导致重复释放
std::shared_ptr<int> ptr2(p);

总结

避免手动管理内存带来的繁琐和容易出错的问题。我们今天介绍了三种智能指针:unique_ptrshared_ptrweak_ptr
每种智能指针都有各自的使用场景。unique_ptr用于管理独占式所有权的对象,它不能拷贝但可以移动,是最轻量级和最快的智能指针。shared_ptr用于管理多个对象共享所有权的情况,它可以拷贝和移动。weak_ptr则是用来解决shared_ptr循环引用的问题。

下一节,我们将自己动手,从零实现一个C++智能指针。敬请期待

本文转载于网络 如有侵权请联系删除

相关文章

  • 生信入门必须掌握的 30 个 Linux 命令

    学习生物信息,Linux是必须掌握的内容,其实常用的Linux命令也就30个左右,而且这些命令都是单词的简写,记忆起来并不困难。这里列出了常用的30个命令。1.cdChangedirectory.修改工作目录,cd和ls应该是使用最多的两个命令,尤其是对于Linux目录结构不熟的用户。cd/#进入根目录 cd-#返回上次的目录 cd#返回home目录 cd~#返回home目录 cd../#返回上一级目录 复制2.lsListfiles.-a列出包括.a开头的隐藏文件的所有文件 -A通-a,但不列出"."和".." -l列出文件的详细信息 -c根据ctime排序显示 -t根据文件修改时间排序 ---color[=WHEN]用色彩辨别文件类型WHEN可以是'never'、'always'或'auto'其中之一 复制3.pwdPrintworkingdirectory. $pwd /home/wangtong 复制4.shScript.运行脚本的命令,脚本是包含很多命令的一个文件,sh这个文件

  • BIB | pNovo3:使用排序学习框架进行精确的多态从头测序

    作者|尹成林 编辑|尹成林 校对|李仲深 今天给大家介绍的是中国科学院计算机研究所发表在BriefingsinBioinformatics上的一篇文章“pNovo3:precisedenovopeptidesequencingusingalearning-to-rankramework”。基于串联质谱数据的新肽测序是猎枪蛋白质组学的关键技术,可以用于识别没有任何数据库的肽和组装未知蛋白质。然而,由于串联质谱的离子覆盖率低,如果某些连续的氨基酸的支持性片段离子全部丢失,则无法确定其顺序。这就导致了从头测序的低精确度。为了解决这个问题,作者开发了pNovo3,它使用了一个排名学习的框架来区分每个光谱的相似候选肽。精度比其他三种最先进的从头测序算法高出11-89%。与同样使用深度学习方法的新开发的DeepNovo相比,pNovo3在9个数据集上仍能识别21-50%。一、研究背景基于质谱数据的猎枪式蛋白质组学研究着重于高通量的肽和蛋白质鉴定。主要方法是使用专门的序列数据库来识别肽和蛋白质,如SEQUEST。主要方法是使用专门的序列数据库来识别肽和蛋白质,然而尽管数据库搜索具有无可争议的普及性,

  • Android使用CardView实现圆角对话框

    前言:随着用户体验的不断的加深,良好的UI视觉效果也必不可少,以前方方正正的对话框样式在APP已不复存在,取而代之的是带有圆角效果的Dialog,之前设置对画框的圆角效果都是通过drawable/shape属性来完成,随着GoogleAPI的不断更新,API21(Android5.0)添加了新的控件CardView,这使得圆角的实现更加方便快捷。效果图:导入CardView依赖(API21新控件)implementation'com.android.support:cardview-v7:26.1.0'复制1.布局引用<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layo

  • 平庸前端码农之蜕变 — AST

    前言首先,先说明下该文章是译文,原文出自《ASTforJavaScriptdevelopers》。很少花时间特地翻译一篇文章,咬文嚼字是件很累的事情,实在是这篇写的太棒了,所以忍不住想和大家一起分享。OK,我们直接进入正题。为什么要谈AST(抽象语法树)?如果你查看目前任何主流的项目中的devDependencies,会发现前些年的不计其数的插件诞生。我们归纳一下有:javascript转译、代码压缩、css预处理器、elint、pretiier,等。有很多js模块我们不会在生产环境用到,但是它们在我们的开发过程中充当着重要的角色。所有的上述工具,不管怎样,都建立在了AST这个巨人的肩膀上。所有的上述工具,不管怎样,都建立在了AST这个巨人的肩膀上我们定一个小目标,从解释什么是AST开始,然后到怎么从一般代码开始去构建它。我们将简单地接触在AST处理基础上,一些最流行的使用例子和工具。并且,我计划谈下我的js2flowchart项目,它是一个不错的利用AST的demo。OK,让我们开始吧。什么是AST(抽象语法树)?❝Itisahierarchicalprogramrepresenta

  • 美摄 - 助力打造完善的音视频解决方案

    随着短视频成为人们竞相追逐的新风口,移动端音视频处理需求与日俱增。如何低成本、高效率地处理音视频,并且最大程度的适应移动互联网的不同应用需求成为至关重要的问题。本次分享以美摄SDK的音视频处理框架为依据,介绍在移动端高效处理音视频的解决方案,以及人工智能在音视频处理方面的应用。文/刘路伟整理/LiveVideoStack大家好,我是来自美摄科技公司的刘路伟,这次与大家分享的主题是美摄SDK如何帮助客户打造完善的音视频解决方案。我会分为两个部分来讲解,一个就是美摄能够做到什么事情;二是从技术层面如何实现这些事情。首先来介绍一下我们公司,美摄原先是新奥特集团的一个子公司,是从新奥特集团中分划出来的,核心团队来自新奥特集团的一个项目的技术团队,拥有比较先进的广电研发经验,也取得过一些成就。美摄SDK成立的时间不长,从2016年到现在三年多的时间,但是服务了很多头部的客户,并且为客户进行定制化的解决方案。1.美摄SDK产品及服务方案1.1产品介绍美摄SDK主要功能有图中所列的这些,但也不仅限于这几点。美摄SDK最基础的功能就是视频的拍摄&编辑,在拍摄时从采集端加入滤镜、特效、贴纸等效果

  • 干货|TensorFlow数据量少的时候却占GPU显存比较多

    作者:Mary_M问题背景:最近在做一个文本多分类的项目,来源于实际的需求场景。具体的情况不多说,但是有一点需要说明的是,场景有多个,每个场景下都有自己的数据,这些数据都是短文本数据。不同的是每个场景中含有的数据量不同。一开始我们做的时候是从数据量最大的场景入手,有107万条训练数据,单词有7万多个,分类效果还不错,不做任何数据预处理,测试集上准确率有94%,这个时候显示的GPU显存是700MB。接着做数据量小一点儿的场景,有70几万条数据,单词有6万多个,发现这个时候的GPU显存有3000多MB。训练时候的参数一模一样。按道理应该单词数多的那个显存比较大才对。而且按照我们的参数计算GPU显存就应该只有几百MB才是正常的。虽然从准确率上看程序应该没问题,但这个问题不解决会让我怀疑自己。 解决思路  先去搜索了一圈,发现大家都在说的是tensorflow会占满显存的问题(也有可能是我自己没对这个问题表述正确导致没搜索到结果)。  然后思考是不是我的数据有问题。因为虽然数据类似,但是毕竟来源于不同的场景。于是我就回到数据量大的那个场景,从中选了70万条数据训练模型。这个时候观察GPU显存,

  • DevOps 转型,只有工具是远远不够的!

    敏捷软件开发已经打破了需求分析、测试、开发之间的壁垒。在软件开发流程中,开发与运维之间面临着相同的隔离问题。DevOps运动的目标就是打破开发与运维之间的壁垒,鼓励开发与运维之间的协作。新运维工具的出现以及敏捷工程实践的建立使得DevOps变成了可能[1],但对于DevOps好处的认识还远远不够,即便拥有最好的工具,如果我们没有正确的文化,DevOps仅仅是一个时髦的词汇而已。DevOps文化的基本特征是开发和运维角色之间的不断增强的协作。在团队级和组织级都需要文化的转变一支持这种协作。责任共担责任共担是DevOps的团队文化之一,责任共担鼓励团队进一步的协作。如果系统运行与维护的工作交给了其他团队负责,开发团队一般都不会关心具体的运维工作。当开发团队共同分担系统生命周期中的运维工作与责任时,开发团队就能理解运维团队的痛苦,就能主动简化开发和运维中繁琐的工作(例如:自动化部署和完善日志)。他们也可以通过生产环境系统监控获取额外的需求。当运维团队主动承担系统的业务目标时,运维团队可以和开发团队更紧密的合作,以理解运维需求并提供支持。在实践中,协作往往开始于开发团队意识到需要了解更多的运维

  • Atitit php db mysql api<?php$mysql_conf = array( ‘host‘ => ‘localhost‘, ‘db‘ => ‘mysql

    Atititphpdbmysqlapi     php与mysql的连接有三种API接口,分别是:PHP的MySQL扩展、PHP的mysqli扩展、PHP数据对象(PDO)。在这三种方法中,“民间”很多是倾向于使用PDO,因为其不担有跨库(可以和各个数据库连接和处理)的优点,更有读写速度快的特点。PDO不仅能防止了sql注入问题,同时是面向对象的,所以不管操作还是使用都是挺方便的!今天分享下PHP5中使用PDO操作数据库的方法! 1.PDO简介 PDO(PHPDataObject)是PHP5中加入的东西,是PHP5新加入的一个重大功能,因为在PHP5以前的php4/php3都是一堆的数据库扩展来跟各个数据库的连接和处理,什么php_mysql.dll、php_pgsql.dll、php_mssql.dll、php_sqlite.dll等等。PHP6中也将默认使用PDO的方式连接         <?php$mysql_conf=array(    'host'=>'local

  • 面试官, TCP连接状态中的TIME_WAIT表示什么

    答案其实就藏在下面这张图里,接下来我们就一步一步看这张图,图看完了,答案也就有了。 状态名词解释 整个图client和server的状态都是从ClOSED开始流转 LISTEN:表示server在等待一个远程的tcp请求 SYN-SENT:表示client在发布一个连接请求之后等待server回复对应的连接请求 SYN-RECEIVED:表示在server和client都发出一次连接请求的之后,在等待一次最后的确认(ACK) ESTABLISHED:表示连接已经建立,数据可以被发送和接收 FIN-WAIT-1:表示在等待另一端的断开请求(FIN),或者另一端收到断开请求并回复的确认请求(ACK) FIN-WAIT-2:表示在等待另一端的断开请求(FIN) CLOSE-WAIT:表示等待本端的断开请求,确保本端也没有数据发送了. CLOSING:表示已经收到另一端的断开请求(FIN),在等待另一端确认收到自己的断开请求(ACK) LAST-ACK:表示server在等待client的确认信号(ACK),以确认client收到了自己发出的FIN和ACK TIME-WAIT:表示等足够的时

  • 高三划水日记

    因为退役了,暂时没有明确的目标,所以不叫训练日记了,叫划水日记好了2333 发现河北一本线不是很难考,所以高三不会非常艰难?但还是艰难的....大概就是要很会偷懒挤时间才能做成一两件之前没机会做成的事情吧... 可能有时会屯很多天一起更? 7.23开坑. 7.23 上午在绍兴回吴桥的火车上.思考人生.听说暑假放到8.10.吼. 这几天主要搞文化课...搞点五三王后雄教材帮 高三还是想写写OI题,写写博客.然而我这老年选手也不能写动什么毒瘤题目....就咸鱼一波刷bzoj好了....比如先把第7页的USACOsilver切通 可能时间原因高三并不能打什么线上比赛了... 今天晚上atcodergrandcontest可以回家打,可能是今年最后一次线上打比赛了.希望能渡劫成功. UPD:退役选手好好刷USACOsilver去,打什么线上比赛....只会A题,怒掉100多的rating... 7.24 收到了快递. 五三和必刷题好厚啊 怎么快递送得这么快... 7.25 必刷题和五三都好难啊....钦定文化课GG啊... 7.26 出点水题,写点课件... 7.27 出点水题,写点课件...

  • Spring Bean的生命周期(非常详细)

    Spring作为当前Java最流行、最强大的轻量级框架,受到了程序员的热烈欢迎。准确的了解SpringBean的生命周期是非常必要的。我们通常使用ApplicationContext作为Spring容器。这里,我们讲的也是ApplicationContext中Bean的生命周期。而实际上BeanFactory也是差不多的,只不过处理器需要手动注册。  转载请注明地址http://www.cnblogs.com/zrtqsk/p/3735273.html,谢谢。 一、生命周期流程图:   SpringBean的完整生命周期从创建Spring容器开始,直到最终Spring容器销毁Bean,这其中包含了一系列关键点。   若容器注册了以上各种接口,程序那么将会按照以上的流程进行。下面将仔细讲解各接口作用。   二、各种接口方法分类 Bean的完整生命周期经历了各种方法调用,这些方法可以划分为以下几类: 1、Bean自身的方法  :  这个包括了Bean本身调用的方法和通过配置文件中<bean>的init-method和destroy-method指定的方法

  • Kettle 连接失败 Oracle 数据库报 ora-12505 的解决方法(转)

    用kettle新建DB连接的时候总是报错,可是用plsql连接是可以连上,错误信息大致如下: 错误连接数据库[MIS]:org.pentaho.di.core.exception.KettleDatabaseException:ErroroccuredwhiletryingtoconnecttothedatabaseErrorconnectingtodatabase:(usingclassoracle.jdbc.driver.OracleDriver)Listenerrefusedtheconnectionwiththefollowingerror:ORA-12505,TNS:listenerdoesnotcurrentlyknowofSIDgiveninconnectdescriptorTheConnectiondescriptorusedbytheclientwas:10.9.202.67:1521:ORCLorg.pentaho.di.core.exception.KettleDatabaseException:Erroroccuredwhiletryingtoconnectto

  • sparse用法matlab官方说明

    sparse   创建稀疏矩阵 全页折叠 语法 S=sparse(A) S=sparse(m,n) S=sparse(i,j,v) S=sparse(i,j,v,m,n) S=sparse(i,j,v,m,n,nz)   说明 示例 S=sparse(A) 通过挤出任何零元素将满矩阵转换为稀疏格式。如果矩阵包含许多零,将矩阵转换为稀疏存储空间可以节省内存。 示例 S=sparse(m,n) 生成 m×n 全零稀疏矩阵。 示例 S=sparse(i,j,v) 根据 i、j 和 v 三元组生成稀疏矩阵 S,以便 S(i(k),j(k))=v(k)。max(i)×max(j) 输出矩阵为 length(v) 非零元素分配了空间。sparse 将 v 中下标重复(在i 和 j 中)的元素加到一起。 如果输入 

  • Hadoop集群扩容

    一、添加新的节点(热部署)   1.克隆一台虚拟机作为新的节点,修改IP、主机名   2.修改namenode的/etc/hosts中的IP地址映射(这个步骤只是为了方便记忆,可以不做,在namenode的slaves添加ip地址即可)      3.修改namenode的slaves,添加新的节点      4.配置新节点的免密登陆 ssh-keygen//生成公钥和私钥 ssh-copy-id主机名//传递公钥复制   5.单独启动新节点datanode hadoop-daemon.shstartdatanode复制   6.验证 二、纵向扩容(挂载新的硬盘)   1.新增硬盘  右键虚拟机 >> 设置 >> 添加 >> 硬盘  重启reboot   2.使用命令lsblk查看系统的硬盘使用状况      3.硬盘分区  fdisk/dev/sdb   常用命令:m查看帮助  n分区  p查看分区表  w保存分区信息   4.硬盘分区格式化  mkfs.xf

  • 11.10

    判断数据库是否存在:if exists (select * from sys.databases where name = ’数据库名’)   数据库中批处理(go); 数据库建库/建表:create database/table 库名/表名; insert into 表名 values = insert 表名 values identity(1000,1)------自增:从1000开始,每次增加1 tell char(11) unique not null,--唯一   添加数据: insert into Info values('张三','男','12345678910')insert into Info values('张三',default,'12345678911')i

  • ubuntu下root和安装mysql

       sudopassword创建新的root密码:    1、用当前登录用户打开终端,在终端输入命令sudopasswd,输入当前用户的密码然后回车        2、会提示输入新密码,输入完成后回车(http://www.linuxidc.com/Linux/2014-04/100489.htm)    3、然后提示再输入一次新密码以确认,然后回车,设置成功 1zhuzhu@zhuzhu-K53SJ:~$sudopasswd 2输入新的UNIX密码: 3重新输入新的UNIX密码: 4passwd:已成功更新密码 5zhuzhu@zhuzhu-K53SJ:~$su 6密码: 7root@zhuzhu-K53SJ:/home/zhuzhu#复制    注意:这个新密码就是root的密码,可以与当前用户的密码不同。    在终端中输入suroot,然后输入root的密码,验证成

  • 1.9 分布式协调服务-Zookeeper(二)

    zoo.cfg配置文件分析 tickTime=2000 zookeeper中最小的时间单位长度(ms) initLimit=10 follower节点启动后与leader节点完成数据同步的时间 syncLimit=5leader节点和follower节点进行心跳检测的最大延时时间 dataDir=/tmp/zookeeper 表示zookeeper服务器存储快照文件的目录 dataLogDir表示配置zookeeper事务日志的存储路径,默认指定在dataDir目录下 clientPort表示客户端和服务端建立连接的端口号:2181 zookeeper中的一些概念 数据模型 zookeeper的数据模型和文件系统类似,每一个节点称为:znode. 是zookeeper中的最小数据单元。每一个znode上都可以 保存数据和挂载子节点。从而构成一个层次化的属性结构 节点特性 持久化节点 :节点创建后会一直存在zookeeper服务器上,直到主动删除 持久化有序节点:每个节点都会为它的一级子节点维护一个顺序 临时节点:临时节点的生命周期和客户

  • GEE影像集合ImageCollection中的统计计算

    GEE影像集合ImageCollection中的统计计算 a.reduce(reducer,parallelScale) reducer:计算方法,如均值、最大值等 parallelScale:缩放比例,为一个后台优化参数,如果计算内存溢出可以设置2、4等 影像集合中的reduce主要是所有影像提取对应波段计算生成单景影像。此外,需要注意EarthEngine中的所有操作底层本质都是在操作像素,这里计算结果为逐像素的结果。 案例:计算ImageCollection内的NDVI均值影像 varroi=/*color:#98ff00*/ee.Geometry.Polygon( [[[114.62959747314449,33.357067677774594], [114.63097076416011,33.32896028884253], [114.68315582275386,33.33125510961763], [114.68178253173824,33.359361757948754]]]); Map.centerObject(roi,7); Map.setOptions(

  • Android高级音频应用

    说到音频应用,首先想到的就是音乐播放器。有些播放器可以播放流媒体,有些可以播放本地音乐文件。随着Android平台的演变,需要更多高级的音频API。好在谷歌新增了这方面的API,支持低延迟的音频流媒体和录制。 Android音频API提供了一些高级的功能,开发者可以把它们集成到自己的应用中。有了这些API,现在可以更容易地实现VoIP应用程序,构建定制的流媒体音乐客户端,实现低延迟的游戏音效。此外,还有提供文本到语音转换以及语音识别的API,用户可以直接使用音频和应用交互,而不需要使用用户界面或者触控技术。 低延迟音频 Android有四个用来播放音频的API(算上MIDI的话一共五个)和三个用来录音的API。接下来会简要的介绍这些API,以及一些高级用法示例。 ①音频播放API 音乐播放默认使用MediaPlayer。该类适合播放音乐或者视频,既能播放流式资源,还可以播放本地文件。每个MediaPlayer都有一个关联的状态机,需要在应用程序中跟踪这些状态。开发者可以使用MediaPlayer类的API在自己应用中嵌入音乐或者视频播放功能,而无需额外处理或者考虑延

  • iOS 技术篇:从使用到了解block底层原理 (二)

    block实质 序言 上篇文章中主要通过简单的demo展示了block的使用场景,本篇将基于上篇文章iOS技术篇:从使用到了解block底层原理(一)进一步了解block底层的实现原理。 block作为一种"带有自动变量值的匿名函数",在实际编译时,我们无法转换成我们能够理解的源代码,但clang(LLVM编译器)具有转化为我们可读源代码的功能。终端输入如下命令行,可获取.cpp文件。 clang-rewrite-objc源代码文件名复制 在main.m中实现如下 intmain(intargc,constchar*argv[]){ @autoreleasepool{ void(^myBlock)(void)=^{ NSLog(@"testtest"); }; myBlock(); } return0; }复制 通过clang我们获取到main.cpp文件,打开文件我们可以看到大约10w行代码,当然我们不用从头到尾细细分析每块的功能。我们只需要看最后几行然后步步分析就可以。 intmain(intargc,constchar*argv[]){ /*@autoreleasepool*/{

  • 在树莓派上部署asp.net

     今天成功的在树莓派上部署asp.net呢。之前在unbuntu上测试成功了,结果今天操作的时候又不会操作了,主要对Linux太不熟悉了,找资料,资料又不多,这次赶紧记录下来,以备下次查阅。 我用的mono+xsp2。 安装mono的教程网上很多,我就不具体写了,下载好大神在百度网盘上的压缩包,在window上解压缩好后,用ssh工具直接传过去就行了。 然后安装xsp2 安装好之后依旧用ssh工具传过去网站 悲催的是传过去之后我忘了怎么操作了,后来才知道,用cd命令切换到test目录下,然后执行xsp2命令就可以启动网站了 然后就可以访问这个网站了,端口就是上边提示的8080端口 整个工程还是有点艰辛的,我都有点想放弃,该用php了,下次写一篇我安装树莓派系统,并实现图形化远程界面的过程记录下来

相关推荐

推荐阅读