同一块内存,连续两次memset,耗时相差4倍!揪出隐藏的性能杀手!

article/2025/6/18 1:30:31

大家好,我是江南一散人,本文是程序性能调优系列专题第六篇

本专题除讲解常见性能问题以及分析、调优手段外,还会重点讲解一些对系统性能至关重要,却又经常被忽视的高级话题,如Cache、指令流水线、Superscalar、SIMD、分支预测、内存屏障等。此外,还会涉及到编译器、操作系统等话题。

有这么一道题:

问:

  1. 1. 三次memset的性能有差异吗?
  2. 2. 为什么?
  3. 3. 如何调优?

该如何回答呢?

先简单验证下这三次memset的性能到底有没有差异。

测试代码

代码很简单,申请一块内存,连续三次调用memset,并且测量这三次memset的耗时:

编译运行一下:

第一次memset耗时约0.66秒,第二次和第三次耗时0.17秒,这是为什么呢?

内容提要

本文会详细分析这三次memset的性能差异的原因,并给出优化方案,最终使得三次memset的性能基本一致,结果如下:

在解释这三次memset的性能差异以及优化方案之前,需要先介绍一些关于内存管理的基础知识。

虚拟地址

我们知道,应该程序只能看到虚拟地址,必须要先转换成物理地址,然后才能通过地址总线访问到物理内存。

那么,虚拟地址是怎么转换为物理地址的呢?

这个过程有点抽象,且比较复杂,为了方便理解,先举一个例子吧。

注:对MMU不熟悉的童鞋,建议仔细理解一下这个例子,能够很好地帮助理解下文要讲的地址转换过程。如果你已经很熟悉的话,可以跳过,直接看后面的原因分析和优化方法。

实例:设计一个学号查询系统

假设,我们要设计一个学号查询系统,给全国所有的大、中、小学生分配一个全国唯一的学号,给定一个学号能够立即对应到具体的学生。再假设,要求我们必须用一个48bit的数字来表示这个学号。

我们可以这样设计学生学号:用9个bit表示省份,9个bit表示城市,9个bit表示区县,9个bit表示学校,12个bit表示学生在学校内的编号。如下图所示:

接下来,我们来设计这个查询系统。经分析,我们需要至少5种表,分别是:

  • • 省份表:包含所有的省份,一个省份对应一个表项,每个表项是一个指针,指向本省的城市表
  • • 城市表:每个省都有一个自己的城市表,包含本省所有的城市,一个城市对应一个表项,每个表项是一个指针,指向本市的区县表
  • • 区县表:每个市都有一个自己的区县表,包含本市所有的县/区,每个区县对应一个表项,每个表项是一个指针,指向本县/区内的学校表
  • • 学校表:每个县/区都有一个学校表,包含本县/区内所有的大、中、小学,每个学校对应一个表项,每个表项是一个指针,指向本学校的学生表
  • • 学生表:包含一个学校内的所有的学生,每个表项是一个特定的学生。

现在,给定一个学号:0x010203040506,我们可以立即根据这个学号找到对应的学生,如下图所示:

简单解释一下这个过程:

  1. 0. 我们把省份表存放在固定的一个地方,称之为全局表指针,每次查询时直接从这里获取省份表
  2. 1. 根据省份索引在省份表中找到了浙江省的城市表
  3. 2. 根据城市索引在城市表中找到了杭州市的区县表
  4. 3. 根据区县索引在区县表中找到了西湖区的学校表
  5. 4. 根据学校索引在学校表中找到了浙江大学的学生表
  6. 5. 根据学生校内编号在学生表中找到了对应的学生,张三

这个过程是不是很简单?给定任意一个学号,我们立刻可以对应到:A省B市C区D学校的学生E。

不过,虽然这个查询过程很简单,但是每次都要查询5张表才能找到具体的某个学生,这样效率太低了。有没有什么办法可以提高整体查询效率呢?

性能优化:引入快表

经过统计研究,我们发现一个很重要的规律:如果我们查询了一个学生,我们通常会很快再次查询这个学生,或者同一个学校的其他学生

于是,我们又设计了一张新的表,称为快表,把我们最近查询的学生所在的学校对应的学生表直接记录下来,那么下次在查询同一个学校的学生的时候,就可以从快表中直接取到学生表,然后从中找到对应的学生。

比如,我们刚刚查询了学号0x010203040506,也就是浙江省杭州市西湖区浙江大学的张三,于是我们在快查表中记录这么一个表项:

0x01020304->浙江大学学生表

然后,我们又查询学号0x010203047777,先用学校信息0x01020304在快表里查询,发现对应浙江大学的表项,于是直接取得浙江大学的学生表,然后用后面的学生编码0x7777找到浙江大学的学生李四。可见,这个过程比从省表、市表、区县表、学校表逐级查询要快很多。

现在,我们查询另外一个学号0x050903016666,同样,先用学校信息0x05090301在快表里查找,没找到对应学校的表项,于是必须逐级从省表、市表、区县表、学校表里逐级查询,最后找到:江苏省南京市栖霞区南京大学的小明。于是,在快表中再加入一条记录:

0x01020304->浙江大学学生表

0x05090301->南京大学学生表

现在,快表中有浙江大学和南京大学的两条记录了,之后再查询这两个学校的学生时,就可以直接从快表中取得学生表,然后快速定位到具体的学生。

不过,快表的容量很小,最多只能容纳5个学校的记录,当快表被填满时,就要用新的信息把旧的记录替换掉,这样一来,下次再查询旧信息对应学校的学生时,就必须要逐级查询了。

Finally!终于把这个有点蹩脚的例子讲完了,居然占了这么大的篇幅。。。不知是否看明白了呢?

啰里啰唆了半天,这个学号查询系统,跟虚拟地址到物理地址的转换,到底有什么关系呢?

MMU(Memory Management Unit)

从虚拟地址到物理地址的转换,是由CPU内部一个专门的部件自动完成的,也就是MMU(Memory Management Unit)

MMU以Page为单位进行虚拟地址和物理地址的映射,所谓一个Page,就是一块地址连续的内存,不同的CPU,支持的Page大小不同。以x64为例,CPU支持4KB、2MB、1GB大小的Page,但目前大部分系统上默认使用4KB的Page,如Linux。

如果把虚拟地址比作学生学号的话,那么物理地址就是具体的某个学生,而MMU就是我们上面设计的学生ID查询系统。MMU把虚拟地址转换成物理地址的过程,与学生学号对应到具体学生的过程,是非常相似的。

下面以X64 CPU为例进行讲解。X64虽然理论地址宽度是64bit,但目前大部分CPU只支持48bit共256TB的虚拟地址空间。对于4KB大小的页面,MMU采用4级页表进行地址转换,分别是:

  • • PML4(Page Map Level 4),第4级页映射表,每个表项指向一个PDPT
  • • PDPT(Page Directory Pointer Table),页目录指针表,每个表项指向一个PDT
  • • PDT(Page Directory Table),页目录表,每个表项指向一个PT
  • • PT(Page Table),页表,每个表项指向一个物理页面

和学生学号一样,48bit的有效虚拟地址被划分成了5部分:

  • • 9bit PML4索引
  • • 9bit PDPT索引
  • • 9bit PDT索引
  • • 9bit PT索引
  • • 12bit 页内偏移

给定一个虚拟地址0x010203040506,转换为物理地址过程如下图所示:

这个过程和上文讲的学号对应到具体学生的例子非常相似。解释下这个过程:

  1. 0. 从CR3寄存器中取得PML4表的地址。
  2. 1. 根据虚拟地址中的PML4索引字段,在PML4中找到对应的表项PML4E,指向PDPT的地址。
  3. 2. 根据PDPT索引,在PDPT中找到对应的表项PDPTE,指向PDT的地址。
  4. 3. 根据PDT索引,在PDT中找到对应的表项PDTE,指向PT的地址。
  5. 4. 根据PT索引,在PT中找到对应的表项PTE,指向一个物理页面的地址。
  6. 5. 获取到物理页的地址后,再加上页内偏移,就取得了最终的物理地址。

一句话概括,就是根据虚拟地址中各个部分的索引,逐级在PML4、PDPT、PDT、PT中检索,找到物理页面的地址后,再加上页内偏移,就得到最终的物理地址了。

MMU的性能问题

这个转换过程,虽然是MMU硬件自动完成的,但各级页表本身仍然存放在内存中,一次地址转换过程中,可能要多次访问内存,因此,这个转换过程的开销非常大。

如果每次访问内存,MMU都要经过这么复杂的转换才能得到物理地址的话,必然会严重影响程序的性能。怎么解决这个问题呢?

还记得我们是怎么优化学号查询系统的性能的吗?我们把最近查询的学生所在学校的学生表地址,缓存在额外的一张"快表"中,每次查询时,先用学号里的学校信息在快表中查找,如果找到,就直接把快表里缓存的学生表取出来,然后用学号里的校内编号就可以直接对应到具体的学生了,如此就避免了逐级查询的开销。

虚拟地址到物理地址的转换,是不是也可以借鉴这种方法呢?

引入TLB

之前文章讲过,为了解决内存和CPU之间速度严重不匹配的问题,利用程序局部性原理,在CPU和内存之间引入了L1,L2,L3高速缓存,也就是Cache,把最近访问到的数据存放在Cache中,以此减少直接内存访问。

这个思路,在这里同样适用。虚拟地址转换为物理地址时,为了避免每次MMU都必须要逐级查询页表,CPU内部专门设计了一个部件-TLB(Translation Lookaside Buffer),通常称为"快表"TLB本质上是虚拟页地址和物理页地址对应关系的Cache

CPU把最近访问到的虚拟页的地址,和它所映射的物理页的地址,组成一个地址对,直接缓存在TLB中。这样一来,每次通过虚拟地址访问内存时,CPU会先用虚拟页的地址在TLB中查找,如果找到,称为TLB Hit,就直接得到物理页的地址,然后加上页内偏移就能得到物理地址。如果找不到,称为TLB Miss,就必须通过MMU逐级检索页表进行地址转换了。

但是,TLB的容量一般非常小,只能缓存很少的页面地址对,当TLB被占满时,旧的地址对会被新的替换掉

当然,这只是TLB的基本原理,实际上的实现要复杂的多,而且不同的CPU上TLB也各有差异,限于篇幅,不再展开。

malloc和缺页异常

应用程序一般通过glibc来申请内存,如malloc等函数返回的都是虚拟地址。

glibc以内存池的方式进行内存管理,应用程序调用malloc申请内存时,如果内存池中有合适大小的内存块,就直接取出使用,如果没有合适的,就把大的内存块切分成合适的内存块,返回给应用程序。如果连大的内存块都没有的话,就通过系统调用,向内核申请一块新的虚拟内存。

内核为应用程序分配虚拟内存的时候,只是在虚拟地址空间中划分一块指定大小的地址范围出来,并不会立即为其分配物理内存。

应用程序拿到malloc返回的虚拟地址后,就可以访问这块内存空间了。第一次访问这段虚拟地址的一个页面时,由于kernel还没有为其映射物理页面,所以会触发缺页异常(Page Fault),进入内核态缺页异常处理流程。内核会分配一个物理页面,并把物理页面的地址和虚拟地址的映射关系更新到页表中,本次缺页异常处理就结束了,然后切换到用户态,继续被中断的内存访问。

这个过程,对用户态程序是透明的,它甚至根本意识不到缺页异常的存在。当应用程序再次访问到同一个虚拟页面时,就能够正常访问了,不会再次触发缺页异常(除非这个页面又被内核swap出去了)。

整个过程如下图所示:

缺页异常的开销是非常大的,主要因为:

  1. 1. CPU异常处理机制本身的开销。
  2. 2. 用户态和内核态上下文切换的开销。
  3. 3. 分配物理页面的开销。
  4. 4. 如果物理页面不足,可能触发内存回收动作。
  5. 5. 如果物理页面被swap出去,就需要通过disk I/O把页面重新swap进来,这个开销非常大。
  6. 6. 被缺页异常打断的线程,甚至有可能会被调度出去。

看到这里,应该已经明白为什么文章开头test.c中第一次memset要比第二次和第三次性能差那么多了吧?

为什么第一次memset那么慢?

test.c用malloc分配了1GB的虚拟内存,内核并没有立即为其分配物理内存,所以每当第一次访问一个虚拟页面,都会触发缺页异常。

也就意味着,第一次memset的时候,会触发1GB / 4KB = 262144次缺页异常,而当第二次和第三次memset的时候,内核已经分配好了物理内存,不会再次触发缺页异常,所以性能比第一次memset要好的多。

这只是理论分析,现在我们来验证一下。先把第二次和第三次memset注释掉:

编译运行,并用perf统计下一共触发多少次缺页异常:

可以看到,只有一次memset的时候,一共触发了262199次缺页异常,比我们计算的262144多了55次,这是因为程序的数据段、代码段、栈空间等运行时也可能会触发缺页异常。

现在把第二次和第三次memset重新加回去,重新编译运行,再用perf统计一下:

缺页异常仍然触发了262199次,和只有一次memset时一模一样,可见,第二次和第三次memset连一次缺页异常都没触发!

另外,也留意一下,现在执行三次memset时,一共触发了2574501次dTLB-load-misses,我们后面优化之后,会再对比一下这个数据。

现在知道了第一次memset性能差的原因,那么,如何进行优化呢?

一种常用的优化方式是,采用Huge Page替代默认的4KB Page。

Huge Page

随着计算机技术的不断发展,物理内存速度越来越快,容量也越来越大。当前计算机的物理内存动辄就是几十GB,或者上百GB,有些高性能服务器上甚至达到TB的级别。在这个背景下,传统的4KB页面的内存管理,显然对一些内存需求量大的程序已经不适合了。

传统4KB页面的局限

以4GB虚拟内存为例,如果采用4KB页面进行管理,就要有4GB/4KB = 1048576个Page,也就意味着需要1048576个页表项,再加上中间各级页表目录,就会占用大量的内存来存储各级页表。

更重要的是,程序访问这4GB内存,至少要经过1048576次TLB Miss和缺页异常,才能把这4GB虚拟内存全部映射到物理内存。

此外,即便物理内存映射全部完成之后,程序在正常运行时,由于TLB容量极其有限,这么多的页表项必然会引发大量的TLB Miss,严重影响程序性能,尤其当程序局部性不好,内存随机访问比较多的时候(如大量引用和遍历链表等数据结构时),这种性能影响会尤为明显。

前面介绍MMU地址转换的时候讲过,CPU一般支持多种大小的Page,比如X64就支持4KB、2MB、1GB大小的Page。那么,既然传统的4KB页面内存管理,存在各种性能问题,能否用更大的页面呢?

是的,现在的操作系统,虽然默认采用4KB的页面进行内存管理,但同时也支持更大的页面。以Linux为例,内核引入了Huge Page的特性,可以使用2MB或1GB的大页来代替传统的4KB页面。

这样一来,同样的4GB虚拟内存,使用2MB的大页,只需要4GB/2MB = 2048个Page,缺页异常和TLB都会大幅下降,能显著提升程序性能。而用1GB的页面的话,只需4GB / 1GB = 4个Page,此时,缺页异常和TLB Miss的影响被降到了最小。

MMU对大页的支持

对MMU来说,使用更大的页面,虽然和使用4KB的页面本质上没有区别,但是可以减少页表层级。此外,使用大页后,页面映射少了,对TLB的压力也就小了,可以降低TLB Miss的概率。

如X64上,使用2MB的页面,只需要3级页表就可以了,相比4KB的页面,减少一级页表,地址转换过程如下图:

如果使用1GB页面的话,就只需要2级页表,相比4KB页面,减少了2级页表,地址转换过程如下图:

简单来说,Huge Page的引入,可以带来这些好处:

  1. 1. 大大减少Page Fault的次数
  2. 2. 大大降低TLB Miss的概率
  3. 3. 减少了MMU地址转换需要的页表层级,不但节省了内存,还能提高MMU地址转换的效率。
  4. 4. Huge Page可以永驻内存,避免被swap出去。

当然,大量使用Huge Page的话,也可能会导致部分内存的浪费。

Huge Page的应用非常广泛,很多高性能场景中,都会通过使用Huge Page来提升整体性能,如DPDK等。

Linux对Huge Page的支持

Linux支持两种Huge Page:

  • • 一种是标准的Huge Page,需要预先分配,管理和使用起来稍显麻烦,但实际场景中用的比较多。
  • • 另一种叫透明大页(Transparent Huge Pages),可以在使用时动态分配,使用相对简单,但只支持2MB的大页,而且仍然有可能被swap出去。

下面,以我系统上默认支持的2MB的标准Huge Page来验证下,是否能提升第一次memset的性能。

为避免影响,先把透明大页关闭:

echo never > /sys/kernel/mm/transparent_hugepage/enabled

然后,确认下默认支持的Huge Page的大小确实是2MB:

root@ubuntu:test# cat /proc/meminfo | grep Hugepagesize

Hugepagesize: 2048 kB

然后预分配1024个Huge Page,也就是2GB的内存:

root@ubuntu:test# cat /proc/sys/vm/nr_hugepages

0

root@ubuntu:test# echo 1024 > /proc/sys/vm/nr_hugepages

再确认一下:

root@ubuntu:test# cat /proc/meminfo | grep Huge

AnonHugePages: 0 kB

ShmemHugePages: 0 kB

FileHugePages: 0 kB

HugePages_Total: 1024

HugePages_Free: 1024

HugePages_Rsvd: 0

HugePages_Surp: 0

Hugepagesize: 2048 kB

Hugetlb: 2097152 kB

把代码稍微修改一下,以便启用Huge Page:

重新编译运行:

第一次memset耗时降到了从使用4KB页面时的0.659秒,降到了0.238秒,第二次和第三次memset的耗时也稍有降低!

用perf看下性能数据:

缺页异常次数从使用4KB页面时的262199次,降到了568次,而dTLB-load-misses也从2574501次,降到了27004次!

由此可见,与默认的4KB的Page相比,使用2MB的Huge Page确实显著降低了缺页异常和dTLB Miss的数量!

但是第一次memset性能仍然比第二次和第三次慢了很多,还能再继续优化吗?

当然可以!

提前映射页面

使用2MB的Huge Page虽然显著降低了缺页异常,但并没有完全消除,因此第一次memset仍然比第二次和第三次慢了很多。

不过,mmap提供了一个MAP_POPULATE标记,可以在分配内存的时候提前把页面映射好,从而避免运行时的缺页异常

咱们来验证一下,简单修改下代码,调用mmap的时候,加上MAP_POPULATE标记:

重新编译运行:

看到了吧,现在三次memset性能几乎一样了!

最后,再用perf看下缺页异常次数是否有变化:

果然,现在缺页异常只有55次,可见三次memset过程中不会再触发任何缺页异常了!

其他可能的优化点

对于内存需求量大的应用场景,除了Huge Page外,还可以考虑从这些方向进行优化:

  • • 让程序保持较好的局部性,顺序访问优于随机访问,如数组访问优于链表访问。
  • • 预读或预热,如进入关键路径之前,先确保物理内存已经被分配。比如,有些系统设计为了解决这类问题,甚至会专门创建一个helper线程,专门负责预读,不仅适合文件I/O,也适合内存访问量比较大的场景。
  • • 禁用swap。swap虽然可以一定程度上缓解物理内存短缺的问题,但是却可能会影响系统整体性能,尤其在热点路径上,如果发生页面swap,会对程序性能产生严重影响。
  • • 考虑NUMA的影响,程序访问本地node上的内存比访问远程node内存快的多。

这里仅列出几个可能的优化点,供大家参考,限于篇幅,不再展开讨论,后续会写文章专门介绍,感兴趣的童鞋欢迎关注【原点技术】。

欢迎关注: 原点技术,分享真正有用的东西!

技术探讨,欢迎添加作者微信:CreCoding


http://www.hkcw.cn/article/JJlNvndbCR.shtml

相关文章

白沙岛论坛永久会址将对标博鳌“亚洲论坛”

9月29日,沈抚示范区秋季集中开工暨白沙岛论坛永久会址建筑综合体开工奠基仪式隆重举行,项目计划于2024年4月竣工并交付使用,2024年5月白沙岛论坛永久会址这一沈抚示范区城市建设历程中的标志性工程将正式向公众开放。图|沈抚示范区秋季集中开工暨白沙岛论坛永久会址建筑综合…

美足球场惊见恐怖天坑!草皮灯柱遭吞噬,灾难瞬间全录下

▲高登摩尔公园(Gordon Moore Park)足球场出现天坑。(图/路透,下同。) 美国伊利诺州一座足球场突然塌陷,形成直径约100英尺(约30.5公尺)、深度约30英尺(约9.1公尺)的巨型天坑,草皮与灯柱等设施被瞬间吞没,宛如灾难电影真实上演,过程都被监视器拍下。 这起事件26日…

什么是OKR?这就是OKR

OKR(Objectives and Key Results)即目标与关键结果法,可以有效确保员工紧密协作,把精力聚焦在能促进组织成长的、可衡量的贡献上。 https://www.okrt.com/ 工作中你有遇到这些问题吗每天都很忙,一到季度总结却发现并没有什么产出?每天都在开会同步信息,重要信息还是被淹…

陈一发在快手复播,再被封禁

三言科技消息 主播陈一发在五年多的封禁后,昨晚在快手直播,首播人气很旺。不过在几分钟后,直播间被封禁。据悉,快手账号“陈X”共发布了8个视频作品,粉丝有4000余个。 当年陈一发是因为不当言论而遭到封禁。

线缆寿命难搞定,为何你的Cable容易断裂?

装置间连接,不可不认识的Cable SR 在信息科技发达的时代,3C产品已经深入每个人的生活中,不论工作、学习、娱乐,都离不开这些产品,而Cable就是在产品中足具重要性的配件之一,它可以让使用者将不同设备连接在一起,实现数据的传输和显示。例如:使用者用Cable将手机、笔记本…

餐企纷纷降价,萨莉亚逆势涨价,底气从何而来?

涨价上了热搜 很多消费者表示理解 萨莉亚涨价上了热搜,消费者却说还是很便宜。 尽管有人对涨价持保留意见,但从整体上看,消费者对萨莉亚的涨价表现出了较高程度的理解和支持。据《新闻晨报》的一项微博调查显示,约60%的受访者能够接受此次涨价行为,仅有11%的人表示不能接受…

外贸卖家注意,UL认证和UL报告有什么区别,如何办理?

UL简介 UL是美国保险商试验所(Underwriter Laboratories Inc.)的简写。UL始建于1894年,初始阶段,UL主要靠防火保险部门提供资金维持动作,直到1916年,UL才完全自立。发展至今,UL安全试验所是美国最具权威的,也是世界上从事安全试验和鉴定的较大的民间机构。 它是一个独立…

这两所高校,合并!

关注我们 日前,教育部公布《关于同意设置新疆和田学院的函》,同意以和田师范专科学校、新疆维吾尔医学专科学校为基础设立新疆和田学院,同时撤销和田师范专科学校、新疆维吾尔医学专科学校的建制。 函件内容具体如下:新疆维吾尔自治区人民政府: 《新疆维吾尔自治区人民政府…

原创2026年三国合作世界杯,中国男足面临巨大挑战

2026年世界杯标志着首次三国共同主办,由美国、加拿大和墨西哥承办,对世界杯进行了重大改革。国际足联将队伍扩充至48支参赛队伍,亚洲区的晋级名额也从之前的4.5个增加到8.5个,这让中国男足看到了再次闯入决赛圈的希望。进入18强赛对于亚洲球队来说,代表着几乎50%的晋级机会…

惊吓!御龙湾小区:9岁儿子不见了,监控显示跟着陌生女子走出小区?

滕州电视台01 孩子是家长的心头肉,一旦发生意外,最着急的就是家长,这不前几天在我市御龙湾小区,一位家长下班回家后发现孩子不见了,更严重的是通过小区的监控录像,家长看到一个疑似孩子的身影跟着一位陌生女子走出了小区,一时间这位家长是又着急又害怕。于是民警立即连夜…

成绩单亮眼!我国独角兽企业数量全球排名第二

随着胡润研究院于近日发布最新一期全球独角兽企业榜单,我国独角兽企业发展现状也浮出水面。 一方面,《2024全球独角兽榜》数据显示,截至2023年12月31日,中国共有340家独角兽企业,全球排名第二;另一方面,2023年我国新晋独角兽企业数量为56家,其中多为智能制造、能源电力…

一文读懂MRP物料需求计划和计算逻辑

本文作者的版权专著,购买链接如下 根据APICS字典上的定义,MRP物料需求计划(Material Requirements Planning)是一套技术,它使用BOM物料清单数据、库存数据和主生产计划来计算材料的需求。 MRP主要解决的是需要购买多少数量的原料,以及什么时候需要到货的问题。计算的功能…

人生星图丨星座小科普之上升射手座

上升星座系列受到好多伙伴的欢迎, 小巫以后会继续讲解简单的占星知识。 从此看运更轻松, 了解自己,了解运势,接到更多好运! 我们按照四象分类, 来看看火象星座的上升射手座。 对于上升星座知识有了解后,可直接看04部分01 “什么是上升星座以及上升星座的重要性。” 上升…

看了“北大考古女孩”钟芳蓉的近况,我懂了复旦教授的儿子为什么自杀

不走寻常路的钟芳蓉,无条件支持她的父母,一起告诉了我们什么是最好的养育——大人回归自己的边界和职责,孩子找到自己的热望和梦想。这,就是最好的陪伴和养育。 作者:刘娜 来源:闲时花开(ID:xsha369) 01 还记得被“全国考古团宠的女孩”钟芳蓉吗? 她又上热搜了。 讲述…

高人对尼采4个哲学要点的深度提炼,超给力

文眼看世界 在西方哲学史中,尼采是一位饱受争议的哲学家,作为西方哲学史上一位承前启后的人物,从打破传统的形而上学到后期否定基督教,尼采通过宣告上帝死亡而摧毁传统的精神哲学,建立起一种现世的和个体本位的生存哲学,这在当时简直是颠覆式的,在一定意义上他是那个时代…

原创张飞比吕布厉害的证据在哪?在演义和正史中,很轻松就找到了五个

说到三国时期最猛的武将,很多人第一时间会想到的是“三姓家奴”吕布。在那个英雄辈出的年代,有一人曾让吕布闻风丧胆他就是燕人张飞。张飞和吕布的较量,历来是各种演义和戏曲里激动人心的高潮。有不少读者提出疑问,张飞真的有能力战胜吕布吗?这不,咱们今天就来聊聊,究竟…

原创抖音小程序小程序是什么?抖音小程序对企业和品牌有什么用处?小程序怎么制作

随着科技的发展和互联网的普及,各种新兴的营销工具不断涌现,其中,抖音小程序就是近年来备受关注的一种。那么,抖音小程序究竟是什么?它对企业和品牌有何用处?又该如何制作呢?分媒互动将为您一一解答。 一、抖音小程序是什么?简单来说,抖音小程序是一种可以在抖音平台上…

战网国际服如何下载 战网国际服下载教程分享

在战网国际服平台中有优秀的暴雪游戏,比如魔兽世界、暗黑破坏神4、炉石传说,这些游戏都深受全球玩家的喜爱,但是玩家想要游玩到这些游戏,需要拥有战网国际服客户端。很多玩家不知道怎么下载战网国际服,下面小编将为你们分享详细的战网国际服下载教程。战网国际服如何下载 …

抖音加码本地生活服务:外卖业务与“顺手买”功能的战略布局

在数字化浪潮推动下,本地生活服务市场正迎来新一轮的变革。2022年3月,抖音推出“抖音来客”平台,标志着其正式进军本地生活服务领域。两年后的2024年6月15日,抖音宣布“团购到家”业务不再新增商家,并正式上线外卖业务,将原有团购业务迁移至新平台,这一战略调整,无疑为…

3C认证是什么?作用和优势是什么?

3C认证是什么?其实3C认证就是“中国强制性产品认证制度”,英文名为ChinaCompulsoryCertification,英文缩写为“CCC”。3C认证按照中国政府按照国际世贸组织(WTO)有关协议和国际通行规则,为保护广大消费者人身及生命安全、保护环境、保护国家安全、加强产品质量管理,依照法…