core dump管理在linux中的前世今生

目录

一、什么是core dump?

二、coredump是怎么来的?

三、怎么限制coredump文件的产生?

ulimit

半永久限制

永久限制

四、从源码分析如何对coredump文件的名字和路径管理

命名 

管理

一些问题的答案

1、为什么新的ubuntu不能产生coredump了,需要手动管理?

2、systemd是什么时候出现在ubuntu中的?

3、为什么使用脚本管理coredump后ulimit就不能限制coredump文件的大小了。

4、为什么ulimit限制的大小并不准确?

5、使用脚本就没办法限制coredump的大小了嘛?

6、ubuntu现在对coredump文件的管理方式


一、什么是core dump?

        core dump是Linux应用程序调试的一种有效方式,core dump又称为“核心转储”,是该进程实际使用的物理内存的“快照”。分析core dump文件可以获取应用程序崩溃时的现场信息,如程序运行时的CPU寄存器值、堆栈指针、栈数据、函数调用栈等信息。在嵌入式系统开发中是开发人员调试所需必备材料之一。每当程序异常行为产生coredump时我们就可以利用gdb工具去查看程序崩溃的原因。

二、coredump是怎么来的?

        Core dump是Linux基于信号实现的。Linux中信号是一种异步事件处理机制,每种信号都对应有默认的异常处理操作,默认操作包括忽略该信号(Ignore)、暂停进程(Stop)、终止进程(Terminate)、终止并产生core dump(Core)等。

SignalValueActionComment
SIGHUP1TermHangup detected on controlling terminal or death of controlling process
SIGINT2TermInterrupt from keyboard
SIGQUIT3CoreQuit from keyboard
SIGILL4CoreIllegal Instruction
SIGTRAP5CoreTrace/breakpoint trap
SIGABRT6CoreAbort signal from abort(3)
SIGIOT6CoreIOT trap. A synonym for SIGABRT
SIGEMT7Term
SIGFPE8CoreFloating point exception
SIGKILL9TermKill signal, cannot be caught, blocked or ignored.
SIGBUS10,7,10CoreBus error (bad memory access)
SIGSEGV11CoreInvalid memory reference
SIGPIPE13TermBroken pipe: write to pipe with no readers
SIGALRM14TermTimer signal from alarm(2)
SIGTERM15TermTermination signal
SIGUSR130,10,16TermUser-defined signal 1
SIGUSR231,12,17TermUser-defined signal 2
SIGCHLD20,17,18IgnChild stopped or terminated
SIGCONT19,18,25ContContinue if stopped
SIGSTOP17,19,23StopStop process, cannot be caught, blocked or ignored.
SIGTSTP18,20,24StopStop typed at terminal
SIGTTIN21,21,26StopTerminal input for background process
SIGTTOU22,22,27StopTerminal output for background process
SIGIO23,29,22TermI/O now possible (4.2BSD)
SIGPOLLTermPollable event (Sys V). Synonym for SIGIO
SIGPROF27,27,29TermProfiling timer expired
SIGSYS12,31,12CoreBad argument to routine (SVr4)
SIGURG16,23,21IgnUrgent condition on socket (4.2BSD)
SIGVTALRM26,26,28TermVirtual alarm clock (4.2BSD)
SIGXCPU24,24,30CoreCPU time limit exceeded (4.2BSD)
SIGXFSZ25,25,31CoreFile size limit exceeded (4.2BSD)
SIGSTKFLT16TermStack fault on coprocessor (unused)
SIGCLD18IgnA synonym for SIGCHLD
SIGPWR29,30,19TermPower failure (System V)
SIGINFO29A synonym for SIGPWR, on an alpha
SIGLOST29TermFile lock lost (unused), on a sparc
SIGWINCH28,28,20IgnWindow resize signal (4.3BSD, Sun)
SIGUNUSED31CoreSynonymous with SIGSYS

以下情况会出现应用程序崩溃导致产生core dump:

  1. 内存访问越界 (数组越界、字符串无\n结束符、字符串读写越界)
  2. 多线程程序中使用了线程不安全的函数,如不可重入函数
  3. 多线程读写的数据未加锁保护(临界区资源需要互斥访问)
  4. 非法指针(如空指针异常或者非法地址访问)
  5. 堆栈溢出

三、怎么限制coredump文件的产生?

ulimit

        说到限制就不得不提到ulimit工具了,这个工具其实有个坑,他并不是linux自带的工具,而是shell工具,也就是说他的级别是shell层的。

        当我们新开启一个终端后之前终端的全部配置都会消失,并且他还看人下菜碟,每个linux用设置的都是自己的ulimit,比如你有两个用户,在同一个终端下对当前终端配置

一个 ulimit -c 1024

一个ulimit -c 2048

他们的限制都作用在各自的范围

        即便同一个目录的同一个文件,本来这个coredump可以产生4096k个字节那么a的coredump就是1024,b的就是2048当然,不会很准确的限制,后面会从源码上给大家说明为什么。

        还有就是可以通过配置文件,但是这个优先级虽然高但是可以改,这个文件只在重启时被读取一次,后面其它人再来改这个限制你之前的限制也就无效了。

半永久限制

vim /etc/profile
相当于每开一个shell时,自动执行ulimit -c unlimited(表示无限制其它具体数字通常表示多少k)

永久限制

编辑/etc/security/limits.conf,需要重新登录,或者重新打开ssh客户端连接,永久生效

下面就是软限制和硬限制

四、从源码分析如何对coredump文件的名字和路径管理

命名 

        在/etc/sysctrl.conf中保存的是用户给内核传递的参数,这里有个core_pattern参数是告诉内核怎么管理coredump的。

后面直接写等号就表示这个coredump文件的命名

%% 单个%字符

%p 所dump进程的进程ID

%u 所dump进程的实际用户ID

%g 所dump进程的实际组ID

%s 导致本次core dump的信号

%t core dump的时间 (由1970年1月1日计起的秒数)

%h 主机名

%e 程序文件名

管理

kernel.core_pattern=|/usr/bin/coredump_helper.sh core_%e_%I_%p_sig_%s_time_%t.gz

        像上面那样配置core_pattern后内核就可以使用我们指定的脚本去管理coredump文件了。

这个路径必须是绝对路径,前面必须是|前后都不能有空格,coredump文件会作为参数传入脚本。

这里我直接将文件以压缩格式传递给了脚本

#!/bin/shif [ ! -d "/var/coredump" ];thenmkdir -p /var/coredump
fi
gzip > "/var/coredump/$1"

上面的代码就是一个简单的示例可以把coredump都放到var下的coredump目录中,我们还可以添加一些遍历判断操作限制产生coredump的数量的单个coredump的大小。 

#!/bin/bash  # Set the maximum number of files allowed in /var/coredump  
max_files=1000  # Check if /var/coredump directory exists  
if [ ! -d "/var/coredump" ]; then  mkdir -p /var/coredump  
fi  # Get the current number of files in /var/coredump  
current_files=$(ls -1 /var/coredump | wc -l)  # Check if the number of files exceeds the maximum limit  
if [ $current_files -ge $max_files ]; then  # Sort the files based on creation time (oldest first)  sorted_files=$(ls -1t /var/coredump | head -n 1)  # Remove the oldest files to reduce the number of files to below the limit  rm $sorted_files  
fi  # Compress the file and store it in /var/coredump using gzip  
gzip > "/var/coredump/$1"

代码很简陋正常还要有出错管理,异常情况打印到日志备份等等。 

一些问题的答案

1、为什么新的ubuntu不能产生coredump了,需要手动管理?

        因为现在的ubuntu使用的是systemd,在这里有些服务会对内核管理coredump的接口做配置,导致coredump文件被服务写到接口的脚本管理了。

2、systemd是什么时候出现在ubuntu中的?

        systemd是在Ubuntu 15.04版本中首次出现的。在此之前,Ubuntu使用Upstart作为默认的init系统。然而,从Ubuntu 15.04开始,Ubuntu采用了systemd作为默认的init系统和服务管理器。systemd是一个用于启动、停止和管理系统进程的软件套件,它提供了更快的启动速度、更好的系统资源管理和更强大的服务控制能力。 

        而在Upstart之前用的才是SysVinit。

3、为什么使用脚本管理coredump后ulimit就不能限制coredump文件的大小了。

这个问题就要看源码了

void do_coredump(const siginfo_t *siginfo)
{struct core_state core_state;struct core_name cn;struct mm_struct *mm = current->mm;struct linux_binfmt * binfmt;const struct cred *old_cred;struct cred *cred;int retval = 0;int flag = 0;int ispipe;struct files_struct *displaced;bool need_nonrelative = false;bool core_dumped = false;static atomic_t core_dump_count = ATOMIC_INIT(0);struct coredump_params cprm = {.siginfo = siginfo,.regs = signal_pt_regs(),.limit = rlimit(RLIMIT_CORE),/** We must use the same mm->flags while dumping core to avoid* inconsistency of bit flags, since this flag is not protected* by any locks.*/.mm_flags = mm->flags,};audit_core_dumps(siginfo->si_signo);binfmt = mm->binfmt;if (!binfmt || !binfmt->core_dump)goto fail;if (!__get_dumpable(cprm.mm_flags))goto fail;cred = prepare_creds();if (!cred)goto fail;/** We cannot trust fsuid as being the "true" uid of the process* nor do we know its entire history. We only know it was tainted* so we dump it as root in mode 2, and only into a controlled* environment (pipe handler or fully qualified path).*/if (__get_dumpable(cprm.mm_flags) == SUID_DUMP_ROOT) {/* Setuid core dump mode */flag = O_EXCL;		/* Stop rewrite attacks */cred->fsuid = GLOBAL_ROOT_UID;	/* Dump root private */need_nonrelative = true;}retval = coredump_wait(siginfo->si_signo, &core_state);if (retval < 0)goto fail_creds;old_cred = override_creds(cred);ispipe = format_corename(&cn, &cprm);if (ispipe) {int dump_count;char **helper_argv;struct subprocess_info *sub_info;if (ispipe < 0) {printk(KERN_WARNING "format_corename failed\n");printk(KERN_WARNING "Aborting core\n");goto fail_unlock;}if (cprm.limit == 1) {/* See umh_pipe_setup() which sets RLIMIT_CORE = 1.** Normally core limits are irrelevant to pipes, since* we're not writing to the file system, but we use* cprm.limit of 1 here as a speacial value, this is a* consistent way to catch recursive crashes.* We can still crash if the core_pattern binary sets* RLIM_CORE = !1, but it runs as root, and can do* lots of stupid things.** Note that we use task_tgid_vnr here to grab the pid* of the process group leader.  That way we get the* right pid if a thread in a multi-threaded* core_pattern process dies.*/printk(KERN_WARNING"Process %d(%s) has RLIMIT_CORE set to 1\n",task_tgid_vnr(current), current->comm);printk(KERN_WARNING "Aborting core\n");goto fail_unlock;}cprm.limit = RLIM_INFINITY;dump_count = atomic_inc_return(&core_dump_count);if (core_pipe_limit && (core_pipe_limit < dump_count)) {printk(KERN_WARNING "Pid %d(%s) over core_pipe_limit\n",task_tgid_vnr(current), current->comm);printk(KERN_WARNING "Skipping core dump\n");goto fail_dropcount;}helper_argv = argv_split(GFP_KERNEL, cn.corename, NULL);if (!helper_argv) {printk(KERN_WARNING "%s failed to allocate memory\n",__func__);goto fail_dropcount;}retval = -ENOMEM;sub_info = call_usermodehelper_setup(helper_argv[0],helper_argv, NULL, GFP_KERNEL,umh_pipe_setup, NULL, &cprm);if (sub_info)retval = call_usermodehelper_exec(sub_info,UMH_WAIT_EXEC);argv_free(helper_argv);if (retval) {printk(KERN_INFO "Core dump to |%s pipe failed\n",cn.corename);goto close_fail;}} else {struct inode *inode;if (cprm.limit < binfmt->min_coredump)goto fail_unlock;if (need_nonrelative && cn.corename[0] != '/') {printk(KERN_WARNING "Pid %d(%s) can only dump core "\"to fully qualified path!\n",task_tgid_vnr(current), current->comm);printk(KERN_WARNING "Skipping core dump\n");goto fail_unlock;}cprm.file = filp_open(cn.corename,O_CREAT | 2 | O_NOFOLLOW | O_LARGEFILE | flag,0600);if (IS_ERR(cprm.file))goto fail_unlock;inode = file_inode(cprm.file);if (inode->i_nlink > 1)goto close_fail;if (d_unhashed(cprm.file->f_path.dentry))goto close_fail;/** AK: actually i see no reason to not allow this for named* pipes etc, but keep the previous behaviour for now.*/if (!S_ISREG(inode->i_mode))goto close_fail;/** Dont allow local users get cute and trick others to coredump* into their pre-created files.*/if (!uid_eq(inode->i_uid, current_fsuid()))goto close_fail;if (!cprm.file->f_op->write)goto close_fail;if (do_truncate(cprm.file->f_path.dentry, 0, 0, cprm.file))goto close_fail;}/* get us an unshared descriptor table; almost always a no-op */retval = unshare_files(&displaced);if (retval)goto close_fail;if (displaced)put_files_struct(displaced);if (!dump_interrupted()) {file_start_write(cprm.file);core_dumped = binfmt->core_dump(&cprm);file_end_write(cprm.file);}if (ispipe && core_pipe_limit)wait_for_dump_helpers(cprm.file);
close_fail:if (cprm.file)filp_close(cprm.file, NULL);
fail_dropcount:if (ispipe)atomic_dec(&core_dump_count);
fail_unlock:kfree(cn.corename);coredump_finish(mm, core_dumped);revert_creds(old_cred);
fail_creds:put_cred(cred);
fail:return;
}

        从源码中可以看到在产生coredump的源码中会对上面的core_pattern进行判断,如果传入了脚本就会走上面的分支,没传入走下面的分支,上面只判断了limit是不是1,1表示不产生coredump,如果不是1就赋值为0,0就是没有限制。

        而下面有这个判断,当已经产生的coredump文件超过ulimit -c的限制时就会停止产生。有一个点需要注意,ulimit-c和这里的limit不是完全对应的,是在shell源码中有转化的,不过大体上还是对应的。

4、为什么ulimit限制的大小并不准确?

还是要看这张图,它每次写入的都是内核设计好的,就写这些。

在外面有个for循环调用do_coredump文件.

int get_signal_to_deliver(siginfo_t *info, struct k_sigaction *return_ka,struct pt_regs *regs, void *cookie)
{struct sighand_struct *sighand = current->sighand;struct signal_struct *signal = current->signal;int signr;if (unlikely(current->task_works))task_work_run();if (unlikely(uprobe_deny_signal()))return 0;/** Do this once, we can't return to user-mode if freezing() == T.* do_signal_stop() and ptrace_stop() do freezable_schedule() and* thus do not need another check after return.*/try_to_freeze();relock:spin_lock_irq(&sighand->siglock);/** Every stopped thread goes here after wakeup. Check to see if* we should notify the parent, prepare_signal(SIGCONT) encodes* the CLD_ si_code into SIGNAL_CLD_MASK bits.*/if (unlikely(signal->flags & SIGNAL_CLD_MASK)) {int why;if (signal->flags & SIGNAL_CLD_CONTINUED)why = CLD_CONTINUED;elsewhy = CLD_STOPPED;signal->flags &= ~SIGNAL_CLD_MASK;spin_unlock_irq(&sighand->siglock);/** Notify the parent that we're continuing.  This event is* always per-process and doesn't make whole lot of sense* for ptracers, who shouldn't consume the state via* wait(2) either, but, for backward compatibility, notify* the ptracer of the group leader too unless it's gonna be* a duplicate.*/read_lock(&tasklist_lock);do_notify_parent_cldstop(current, false, why);if (ptrace_reparented(current->group_leader))do_notify_parent_cldstop(current->group_leader,true, why);read_unlock(&tasklist_lock);goto relock;}for (;;) {struct k_sigaction *ka;if (unlikely(current->jobctl & JOBCTL_STOP_PENDING) &&do_signal_stop(0))goto relock;if (unlikely(current->jobctl & JOBCTL_TRAP_MASK)) {do_jobctl_trap();spin_unlock_irq(&sighand->siglock);goto relock;}signr = dequeue_signal(current, &current->blocked, info);if (!signr)break; /* will return 0 */if (unlikely(current->ptrace) && signr != SIGKILL) {signr = ptrace_signal(signr, info);if (!signr)continue;}ka = &sighand->action[signr-1];/* Trace actually delivered signals. */trace_signal_deliver(signr, info, ka);if (ka->sa.sa_handler == SIG_IGN) /* Do nothing.  */continue;if (ka->sa.sa_handler != SIG_DFL) {/* Run the handler.  */*return_ka = *ka;if (ka->sa.sa_flags & SA_ONESHOT)ka->sa.sa_handler = SIG_DFL;break; /* will return non-zero "signr" value */}/** Now we are doing the default action for this signal.*/if (sig_kernel_ignore(signr)) /* Default is nothing. */continue;/** Global init gets no signals it doesn't want.* Container-init gets no signals it doesn't want from same* container.** Note that if global/container-init sees a sig_kernel_only()* signal here, the signal must have been generated internally* or must have come from an ancestor namespace. In either* case, the signal cannot be dropped.*/if (unlikely(signal->flags & SIGNAL_UNKILLABLE) &&!sig_kernel_only(signr))continue;if (sig_kernel_stop(signr)) {/** The default action is to stop all threads in* the thread group.  The job control signals* do nothing in an orphaned pgrp, but SIGSTOP* always works.  Note that siglock needs to be* dropped during the call to is_orphaned_pgrp()* because of lock ordering with tasklist_lock.* This allows an intervening SIGCONT to be posted.* We need to check for that and bail out if necessary.*/if (signr != SIGSTOP) {spin_unlock_irq(&sighand->siglock);/* signals can be posted during this window */if (is_current_pgrp_orphaned())goto relock;spin_lock_irq(&sighand->siglock);}if (likely(do_signal_stop(info->si_signo))) {/* It released the siglock.  */goto relock;}/** We didn't actually stop, due to a race* with SIGCONT or something like that.*/continue;}spin_unlock_irq(&sighand->siglock);/** Anything else is fatal, maybe with a core dump.*/current->flags |= PF_SIGNALED;if (sig_kernel_coredump(signr)) {if (print_fatal_signals)print_fatal_signal(info->si_signo);proc_coredump_connector(current);/** If it was able to dump core, this kills all* other threads in the group and synchronizes with* their demise.  If we lost the race with another* thread getting here, it set group_exit_code* first and our do_group_exit call below will use* that value and ignore the one we pass it.*/do_coredump(info);}/** Death signals, no core dump.*/do_group_exit(info->si_signo);/* NOTREACHED */}spin_unlock_irq(&sighand->siglock);return signr;
}

哪次判断超出了就会停止生成.

5、使用脚本就没办法限制coredump的大小了嘛?

        可以的,但是limit这个系统调用肯定是不行了,源码中我们就看到了人家都不鸟你。但是我们可以ulimit -f,这个脚本coredump文件从内核态到用户态是通过这个传入的脚本,所以直接ulimit -f限制脚本生成的全部文件大小就ok了,但是这里要写成正常两倍大小因为是先获取在写入,我们一个字节计算两次,这次限制的大小就完全准确了,也有个坏处就是文件会损坏限制住了也没法去看这个coredump。

6、ubuntu现在对coredump文件的管理方式

        由于使用systemd机制,所以现在的coredump是以服务的方式存在的,为了可以更好的保存和规范化管理,coredump内容被放到了日志中,使用coredump@和socket服务共同实现,将coredump文件从内核态转移到用户态后又用了socket机制做过滤和写入日志。完美限制大小和内容。只要日志管理的好可以想看任何时候的有用的coredump。

---------------------------------------------------------------------------------------------------------------------------------

        这是我工作中遇到的第一个做了两周的问题的一部分,当时贼痛苦各种查资料翻源码,好在最后想到了还算不错的解决方案,工作的提升是真的大,不止是技术,主要是团队写作能力,做事情的条例,规范化做事才会少出错。这些很重要。还有表达能力,不然你写的永远都是垃圾。下周有时间更新另一半,日志的管理。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/118842.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

一百六十九、Hadoop——Hadoop退出NameNode安全模式与查看磁盘空间详情(踩坑,附截图)

一、目的 在海豚跑定时跑kettle的从Kafka到HDFS的任务时&#xff0c;由于Linux服务器的某个文件磁盘空间满了&#xff0c;导致Hadoop的NodeName进入安全模式&#xff0c;此时光执行hdfs dfsadmin -safemode leave命令语句没有效果&#xff08;虽然显示Safe mode is OFF&#x…

HashMap、LinkedHashMap、ConcurrentHashMap、ArrayList、LinkedList的底层实现。

HashMap、LinkedHashMap、ConcurrentHashMap、ArrayList、LinkedList的底层实现。 HashMap相关问题 1、你用过HashMap吗&#xff1f;什么是HashMap&#xff1f;你为什么用到它&#xff1f;用过&#xff0c;HashMap是基于哈希表的Map接口的非同步实现&#xff0c; 它允许null键…

测试开发【Mock平台】09开发:项目管理(五)搜索、删除和Table优化

【Mock平台】为系列测试开发教程&#xff0c;从0到1编码带你一步步使用Spring Boot 和 Antd React框架完成搭建一个测试工具平台&#xff0c;希望作为一个实战项目对各位的测试开发学习之路有帮助&#xff0c;大奇一个专注测试技术干货原创与分享的家伙。 Mock平台系统项目基本…

数电再回顾

最近&#xff0c;花了点时间回顾数字电路&#xff0c;放几张我觉得比较好的截图&#xff0c;记录学习过程。 附录&#xff1a; 计算机是如何保存1和0的 - 知乎 (zhihu.com) 只读存储器ROM || ROM实现逻辑函数 || 数电 - 知乎 (zhihu.com) ROM的组成原理 -解决方案-华强电子网…

chatgpt谈论日本排放污水事件

W...Y的主页 &#x1f60a; 代码仓库分享 &#x1f495; 近日&#xff0c;世界发生了让人义愤填膺的时间——日本排放核污水。这件事情是那么的突然且不计后果&#xff0c;海洋是我们全人类共同的财产&#xff0c;而日本却想用自己一己私欲将全人类的安全置之度外&#xff0c…

工厂方法模式的概述和使用

目录 一、工厂方法模式概述1. 定义2. 使用动机 二、工厂方法模式结构1. 模式结构2. 时序图 三、工厂方法模式的使用实例四、工厂方法模式的优缺点五、工厂方法模式在Java中应用 原文链接 一、工厂方法模式概述 1. 定义 工厂方法模式(Factory Method Pattern)又称为工厂模式&…

基于Laravel通用型内容建站企业官网系统源码 可免费商用

是一个基于 Laravel 企业内容建站系统。模块市场拥有丰富的功能应用&#xff0c;支持后台一键快速安装&#xff0c;让开发者能快的实现业务功能开发。 系统完全开源&#xff0c;免费且不限制商业使用 2023年08月23日增加了以下12个特性&#xff1a; [新功能] 手机端Banner支持…

数学建模--粒子群算法(PSO)的Python实现

目录 1.开篇提示 2.算法流程简介 3.算法核心代码 4.算法效果展示 1.开篇提示 """ 开篇提示: 这篇文章是一篇学习文章,思路和参考来自:https://blog.csdn.net/weixin_42051846/article/details/128673427?utm_mediumdistribute.pc_relevant.none-task-blog-…

thinkPHP项目搭建

1 宝塔添加站点 &#xff08;1&#xff09;打开命令提示行&#xff0c;输入以下命令&#xff0c;找到hosts文件。 for /f %P in (dir %windir%\WinSxS\hosts /b /s) do copy %P %windir%\System32\drivers\etc & echo %P & Notepad %P &#xff08;2&#xff09;添加域…

数据库-DQL

DQL&#xff1a;用来查询数据库表中的记录 关键字&#xff1a;SELECT 语法&#xff1a; select&#xff1a;字段列表 from&#xff1a;表名列表 where&#xff1a;条件列表 group by&#xff1a;分组列表 having&#xff1a;分组后条件列表 order by&#xff1a;排序字段列表…

2022年12月 C/C++(六级)真题解析#中国电子学会#全国青少年软件编程等级考试

C/C++编程(1~8级)全部真题・点这里 第1题:区间合并 给定 n 个闭区间 [ai; bi],其中i=1,2,…,n。任意两个相邻或相交的闭区间可以合并为一个闭区间。例如,[1;2] 和 [2;3] 可以合并为 [1;3],[1;3] 和 [2;4] 可以合并为 [1;4],但是[1;2] 和 [3;4] 不可以合并。 我们的任务是…

Stable Diffuse 之 本地环境部署/安装包下载搭建过程简单记录

Stable Diffuse 之 本地环境部署/安装包下载搭建过程简单记录 目录 Stable Diffuse 之 本地环境部署/安装包下载搭建过程简单记录 一、简单介绍 二、注意事项 三、环境搭建 git 下载和安装 python 下载和安装 stable-diffusion-webui 下载和安装 测试 stable diffuse w…

构造函数与成员变量初始化

C自学精简教程 目录(必读) 1 为什么需要定义构造函数&#xff1f; 构造函数主要用来给成员变量初始化。 让类对象有一个良好的开始状态。 2 构造函数初始化成员变量 下面我们来完善上一篇文章中的几个构造函数。 让这些构造函数完成给成员变量初始化的职责。 为此&#…

24.排序,插入排序,交换排序

目录 一. 插入排序 &#xff08;1&#xff09;直接插入排序 &#xff08;2&#xff09;折半插入排序 &#xff08;3&#xff09;希尔排序 二. 交换排序 &#xff08;1&#xff09;冒泡排序 &#xff08;2&#xff09;快速排序 排序&#xff1a;将一组杂乱无章的数据按一…

(六)k8s实战-存储管理

一、Volumes 1、HostPath 【使用场景&#xff1a;容器目录 挂载到 主机目录】 【可以持久化到主机上】 将节点上的文件或目录挂载到 Pod 上&#xff0c;此时该目录会变成持久化存储目录&#xff0c;即使 Pod 被删除后重启&#xff0c;也可以重新加载到该目录&#xff0c;该目…

【算法题】1761. 一个图中连通三元组的最小度数

题目&#xff1a; 给你一个无向图&#xff0c;整数 n 表示图中节点的数目&#xff0c;edges 数组表示图中的边&#xff0c;其中 edges[i] [ui, vi] &#xff0c;表示 ui 和 vi 之间有一条无向边。 一个 连通三元组 指的是 三个 节点组成的集合且这三个点之间 两两 有边。 连…

恢复数据的利器:易我数据恢复终身技术版v16.2.0.0

EaseUS Data Recovery Wizard为全球提供数据恢复方案,用于误删数据数据,电脑误删文件恢复,格式化硬盘数据恢复,手机U盘数据恢复等,RAID磁盘阵列数据恢复,分区丢失及其它未知原因丢失的数据恢复,简单易用轻松的搞定数据恢复。 特点描述 - 易我数据恢复中文便携版&#xff0c;无…

Kitchen Hook

双扛厨房排钩&#xff1a;挂刀具

HuggingFace 简介

HuggingFace 简介 0. HuggingFace 简介1. HuggingFace 官网地址2. HuggingFace 标准研发流程3. HuggingFace 工具集4. 编码工具4.1 编码工具介绍4.2 使用编码工具 5. 数据集工具5.1 数据集工具介绍5.2 使用数据集工具 6. 评价指标工具6.1 评价指标工具介绍6.2 使用评价指标工具…

vmware 16增加硬盘容量并在Ubuntu 18.04上边格式化并挂载

参考了《增加 VM虚拟机硬盘容量》 《Linux学习之分区挂载》中有给VMWare 16虚拟机添加一块硬盘的内容&#xff0c;需要先参考添加硬盘。 sudo mkfs.ext4 /dev/sda4给/dev/sda4进行ext4格式化。 sudo mkdir /mountsda4新建一个挂载目录。 sudo mount -t ext4 /dev/sda4 /mo…