导航:首页 > 程序命令 > 程序员的文件碎片

程序员的文件碎片

发布时间:2022-11-25 18:01:16

1. 内存碎片的减少内存碎片

内存碎片是因为在分配一个内存块后,使之空闲,但不将空闲内存归还给最大内存块而产生的。最后这一步很关键。如果内存分配程序是有效的,就不能阻止系统分配内存块并使之空闲。即使一个内存分配程序不能保证返回的内存能与最大内存块相连接(这种方法可以彻底避免内存碎片问题),但你可以设法控制并限制内存碎片。所有这些作法涉及到内存块的分割。每当系统减少被分割内存块的数量,确保被分割内存块尽可能大时,你就会有所改进。
这样做的目的是尽可能多次反复使用内存块,而不要每次都对内存块进行分割,以正好符合请求的存储量。分割内存块会产生大量的小内存碎片,犹如一堆散沙。以后很难把这些散沙与其余内存结合起来。比较好的办法是让每个内存块中都留有一些未用的字节。留有多少字节应看系统要在多大程度上避免内存碎片。对小型系统来说,增加几个字节的内部碎片是朝正确方向迈出的一步。当系统请求1字节内存时,你分配的存储量取决于系统的工作状态。
如果系统分配的内存存储量的主要部分是 1 ~ 16 字节,则为小内存也分配 16 字节是明智的。只要限制可以分配的最大内存块,你就能够获得较大的节约效果。但是,这种方法的缺点是,系统会不断地尝试分配大于极限的内存块,这使系统可能会停止工作。减少最大和最小内存块存储量之间内存存储量的数量也是有用的。采用按对数增大的内存块存储量可以避免大量的碎片。例如,每个存储量可能都比前一个存储量大 20%。在嵌入式系统中采用“一种存储量符合所有需要”对于嵌入式系统中的内存分配程序来说可能是不切实际的。这种方法从内部碎片来看是代价极高的,但系统可以彻底避免外部碎片,达到支持的最大存储量。
将相邻空闲内存块连接起来是一种可以显着减少内存碎片的技术。如果没有这一方法,某些分配算法(如最先适合算法)将根本无法工作。然而,效果是有限的,将邻近内存块连接起来只能缓解由于分配算法引起的问题,而无法解决根本问题。而且,当内存块存储量有限时,相邻内存块连接可能很难实现。
有些内存分配器很先进,可以在运行时收集有关某个系统的分配习惯的统计数据,然后,按存储量将所有的内存分配进行分类,例如分为小、中和大三类。系统将每次分配指向被管理内存的一个区域,因为该区域包括这样的内存块存储量。较小存储量是根据较大存储量分配的。这种方案是最先适合算法和一组有限的固定存储量算法的一种有趣的混合,但不是实时的。
有效地利用暂时的局限性通常是很困难的,但值得一提的是,在内存中暂时扩展共处一地的分配程序更容易产生内存碎片。尽管其它技术可以减轻这一问题,但限制不同存储量内存块的数目仍是减少内存碎片的主要方法。
现代软件环境业已实现各种避免内存碎片的工具。例如,专为分布式高可用性容错系统开发的 OSE 实时操作系统可提供三种运行时内存分配程序:内核 alloc(),它根据系统或内存块池来分配;堆 malloc(),根据程序堆来分配; OSE 内存管理程序 alloc_region,它根据内存管理程序内存来分配。
从 许多方面来看,Alloc就是终极内存分配程序。它产生的内存碎片很少,速度很快,并有判定功能。你可以调整甚至去掉内存碎片。只是在分配一个存储量后,使之空闲,但不再分配时,才会产生外部碎片。内部碎片会不断产生,但对某个给定的系统和八种存储量来说是恒定不变的。
Alloc 是一种有八个自由表的固定存储量内存分配程序的实现方法。系统程序员可以对每一种存储量进行配置,并可决定采用更少的存储量来进一步减少碎片。除开始时以外,分配内存块和使内存块空闲都是恒定时间操作。首先,系统必须对请求的存储量四舍五入到下一个可用存储量。就八种存储量而言,这一目标可用三个 如果 语句来实现。其次,系统总是在八个自由表的表头插入或删除内存块。开始时,分配未使用的内存要多花几个周期的时间,但速度仍然极快,而且所花时间恒定不变。
堆 malloc() 的内存开销(8 ~ 16 字节/分配)比 alloc小,所以你可以停用内存的专用权。malloc() 分配程序平均来讲是相当快的。它的内部碎片比alloc()少,但外部碎片则比alloc()多。它有一个最大分配存储量,但对大多数系统来说,这一极限值足够大。可选的共享所有权与低开销使 malloc() 适用于有许多小型对象和共享对象的 C++ 应用程序。堆是一种具有内部堆数据结构的伙伴系统的实现方法。在 OSE 中,有 28 个不同的存储量可供使用,每种存储量都是前两种存储量之和,于是形成一个斐波那契(Fibonacci)序列。实际内存块存储量为序列数乘以 16 字节,其中包括分配程序开销或者 8 字节/分配(在文件和行信息启用的情况下为 16 字节)。
当你很少需要大块内存时,则OSE内存管理程序最适用。典型的系统要把存储空间分配给整个系统、堆或库。在有 MMU 的系统中,有些实现方法使用 MMU 的转换功能来显着降低甚至消除内存碎片。在其他情况下,OSE 内存管理程序会产生非常多的碎片。它没有最大分配存储量,而且是一种最先适合内存分配程序的实现方法。内存分配被四舍五入到页面的偶数——典型值是 4 k 字节。

2. [编程知识]如何分配内存 内存碎片处理技术

内存碎片是一个很棘手的问题。如何分配内存决定着内存碎片是否会、何时会、如何会成为一个问题。 即使在系统中事实上仍然有许多空闲内存时,内存碎片还会最终导致出现内存用完的情况。一个不断产生内存碎片的系统,不管产生的内存碎片多么小,只要时间足够长,就会将内存用完。这种情况在许多嵌入式系统中,特别是在高可用性系统中是不可接受的。有些软件环境,如 OSE 实时操作系统已经备有避免内存碎片的良好工具,但个别程序员做出的选择仍然会对最终结果形成影响。 “碎片的内存”描述一个系统中所有不可用的空闲内存。这些资源之所以仍然未被使用,是因为负责分配内存的分配器使这些内存无法使用。这一问题通常都会发生,原因在于空闲内存以小而不连续方式出现在不同的位置。由于分配方法决定内存碎片是否是一个问题,因此内存分配器在保证空闲资源可用性方面扮演着重要的角色。 编译时间与运行时间 在许多情况下都会出现内存分配问题。程序员可以通过编译程序和链接程序,为结构、并集、数组和标量(用作局部变量、静态变量或全局变量)方面的数据分配内存,程序员还可以在运行时间使用诸如 malloc()调用命令动态地分配内存。当用编译程序和链接程序完成内存分配功能时,就不会出现内存碎片,因为编译程序了解数据寿命。掌握可供使用的数据寿命,好处在于可以使数据以后进先出的方式叠加起来。这样就可以使内存分配程序工作效率更高,而不会出现内存碎片。一般来说,运行时间内的内存分配是不可叠加的。内存分配在时间上是独立的,从而使得碎片问题难以解决。 图1,内存碎片的几种形式。 内存分配程序浪费内存的基本方式有三种:即额外开销、内部碎片以及外部碎片(图 1)。内存分配程序需要存储一些描述其分配状态的数据。这些存储的信息包括任何一个空闲内存块的位置、大小和所有权,以及其它内部状态详情。一般来说,一个运行时间分配程序存放这些额外信息最好的地方是它管理的内存。内存分配程序需要遵循一些基本的内存分配规则。例如,所有的内存分配必须起始于可被 4、8 或 16 整除(视处理器体系结构而定)的地址。内存分配程序把仅仅预定大小的内存块分配给客户,可能还有其它原因。当某个客户请求一个 43 字节的内存块时,它可能会获得 44字节、48字节 甚至更多的字节。由所需大小四舍五入而产生的多余空间就叫内部碎片。 外部碎片的产生是当已分配内存块之间出现未被使用的差额时,就会产生外部碎片。例如,一个应用程序分配三个连续的内存块,然后使中间的一个内存块空闲。内存分配程序可以重新使用中间内存块供将来进行分配,但不太可能分配的块正好与全部空闲内存一样大。倘若在运行期间,内存分配程序不改变其实现法与四舍五入策略,则额外开销和内部碎片在整个系统寿命期间保持不变。虽然额外开销和内部碎片会浪费内存,因此是不可取的,但外部碎片才是嵌入系统开发人员真正的敌人,造成系统失效的正是分配问题。 定义内存碎片的方法有几种,其中最常用的是: 这一方法适用于外部碎片,但可以修改这一公式使之包括内部碎片,办法是把内部碎片加入到分母中。内存碎片是一个介于 0 和 1 之间的分数。一个碎片为 1(100%)的系统就是把内存全用完了。如果所有空闲内存都在一个内存块(最大内存块)中,碎片为 0%。当所有空闲内存的四分之一在最大内存块中时,碎片为 75%。例子如下:一个系统有 5M 字节的空闲内存,当它可用来分配的最大内存块为 50 k 字节时,其内存碎片为99%。这个 99%内存碎片实例来自开发嵌入式软实时系统期间出现的一种真实情况。当这种碎片程度发生一秒后,系统就崩溃了。该系统在碎片率达到 99% 之前,已经进行了约两周的连续现场测试。这种情况是如何发生的?为什么会发现得如此晚?当然,系统都经过测试,但测试很少超过两个小时。交付前的最后压力测试持续了一个周末。在这样短的测试周期内未必会产生内存碎片的后果,所以就发生了内存碎片需要多长时间才会达到临界值,这一问题很难回答。对某些应用来说,在某些情况下,系统会在用完内存前达到一种稳定状态。而对于另一些应用来说,系统则不会及时达到稳定状态(图 2)。只要消除不确定性因素和风险因素,不产生碎片的内存分配程序(图 3)就能快速达到一种稳定状态,从而有助于开发人员夜晚安稳睡觉。在开发数月甚至数年不再重新启动的长期运行系统时,快速收敛到稳定状态是一个重要因素。在比系统连续运行周期短的时间内,对系统进行适当的测试,这是必不可少的。 图2,这一案例研究把最先适合内存分配程序用于一个嵌入系统项目。系统在现场测试中连续运行了两周,然后碎片率达到 99%。图3,一个不产生碎片的内存分配程序一旦试验应用程序的全部,它就能达到稳定状态。 很难确定哪种内存分配算法更胜一筹,因为每种算法在不同的应用中各有所长(表 1)。最先适合内存分配算法是最常用的一种。它使用了四个指针:MSTART 指向被管理内存的始端;MEND 指向被管理内存的末尾;MBREAK 指向 MSTART 和 MEND 之间已用内存的末端; PFREE 则指向第一个空闲内存块(如果有的话)。 在系统开始运行时,PFREE 为 NULL,MBREAK 指向 MSTART。当一个分配请求来到时,分配程序首先检查 PFREE有无空闲内存块。由于 PFREE 为 NULL,一个具有所请求存储量加上管理标题的内存块就脱离 MBREAK ,然后MBREAK就更新。这一过程反复进行,直至系统使一个内存块空闲,管理标题包含有该存储块的存储量为止。此时,PFREE 通过头上的链接表插入项被更新为指向该内存块,而块本身则用一个指向旧 PFREE 内容的指针进行更新,以建立一个链接表。下一次出现分配请求时,系统就会搜索空闲内存块链接表,寻找适合请求存储量的第一个空闲内存块。一旦找到合适的内存块,它将此内存块分成两部分,一部分返还给系统,另一部分则送回给自由表。 最先适合内存分配算法实现起来简单,而且开始时很好用。但是,经过一段时间后,会出现如下的情况:当系统将内存交给自由表时,它会从自由表的开头部分去掉大内存块,插入剩余的小内存块。最先适合算法实际上成了一个排序算法,即把所有小内存碎片放在自由表的开头部分。因此,自由表会变得很长,有几百甚至几千个元素。因此,内存分配变得时间很长又无法预测,大内存块分配所花时间要比小内存块分配来得长。另外,内存块的无限制拆分使内存碎片程度很高。有些实现方法在使内存空闲时会将邻近的空闲内存块连接起来。这种方法多少有些作用,而最先适合算法与时间共处算法(time co-location)和空间共处算法(spatial co-location)不同,它在使内存块空闲时,无法提高相邻内存块同时空闲的概率。 最佳适合与最差适合分配程序 最佳适合算法在功能上与最先适合算法类似,不同之处是,系统在分配一个内存块时,要搜索整个自由表,寻找最接近请求存储量的内存块。这种搜索所花的时间要比最先适合算法长得多,但不存在分配大小内存块所需时间的差异。最佳适合算法产生的内存碎片要比最先适合算法多,因为将小而不能使用的碎片放在自由表开头部分的排序趋势更为强烈。由于这一消极因素,最佳适合算法几乎从来没有人采用过。 最差适合算法也很少采用。最差适合算法的功能与最佳适合算法相同,不同之处是,当分配一个内存块时,系统在整个自由表中搜索与请求存储量不匹配的内存快。这种方法比最佳适合算法速度快,因为它产生微小而又不能使用的内存碎片的倾向较弱。始终选择最大空闲内存块,再将其分为小内存块,这样就能提高剩余部分大得足以供系统使用的概率。 伙伴(buddy)分配程序与本文描述的其它分配程序不同,它不能根据需要从被管理内存的开头部分创建新内存。它有明确的共性,就是各个内存块可分可合,但不是任意的分与合。每个块都有个朋友,或叫“伙伴”,既可与之分开,又可与之结合。伙伴分配程序把内存块存放在比链接表更先进的数据结构中。这些结构常常是桶型、树型和堆型的组合或变种。一般来说,伙伴分配程序的工作方式是难以描述的,因为这种技术随所选数据结构的不同而各异。由于有各种各样的具有已知特性的数据结构可供使用,所以伙伴分配程序得到广泛应用。有些伙伴分配程序甚至用在源码中。伙伴分配程序编写起来常常很复杂,其性能可能各不相同。伙伴分配程序通常在某种程度上限制内存碎片。 固定存储量分配程序有点像最先空闲算法。通常有一个以上的自由表,而且更重要的是,同一自由表中的所有内存块的存储量都相同。至少有四个指针:MSTART 指向被管理内存的起点,MEND 指向被管理内存的末端,MBREAK 指向 MSTART 与 MEND 之间已用内存的末端,而 PFREE[n] 则是指向任何空闲内存块的一排指针。在开始时,PFREE[*] 为 NULL,MBREAK 指针为 MSTART。当一个分配请求到来时,系统将请求的存储量增加到可用存储量之一。然后,系统检查 PFREE[ 增大后的存储量 ] 空闲内存块。因为 PFREE[ 增大后的存储量 ] 为 NULL,一个具有该存储量加上一个管理标题的内存块就脱离 MBREAK,MBREAK 被更新。 这些步骤反复进行,直至系统使一个内存块空闲为止,此时管理标题包含有该内存块的存储量。当有一内存块空闲时,PFREE[ 相应存储量 ] 通过标题的链接表插入项更新为指向该内存块,而该内存块本身则用一个指向 PFREE[ 相应存储量 ] 以前内容的指针来更新,以建立一个链接表。下一次分配请求到来时,系统将 PFREE[ 增大的请求存储量 ] 链接表的第一个内存块送给系统。没有理由搜索链接表,因为所有链接的内存块的存储量都是相同的。 固定存储量分配程序很容易实现,而且便于计算内存碎片,至少在块存储量的数量较少时是这样。但这种分配程序的局限性在于要有一个它可以分配的最大存储量。固定存储量分配程序速度快,并可在任何状况下保持速度。这些分配程序可能会产生大量的内部内存碎片,但对某些系统而言,它们的优点会超过缺点。 减少内存碎片 内存碎片是因为在分配一个内存块后,使之空闲,但不将空闲内存归还给最大内存块而产生的。最后这一步很关键。如果内存分配程序是有效的,就不能阻止系统分配内存块并使之空闲。即使一个内存分配程序不能保证返回的内存能与最大内存块相连接(这种方法可以彻底避免内存碎片问题),但你可以设法控制并限制内存碎片。所有这些作法涉及到内存块的分割。每当系统减少被分割内存块的数量,确保被分割内存块尽可能大时,你就会有所改进。 这样做的目的是尽可能多次反复使用内存块,而不要每次都对内存块进行分割,以正好符合请求的存储量。分割内存块会产生大量的小内存碎片,犹如一堆散沙。以后很难把这些散沙与其余内存结合起来。比较好的办法是让每个内存块中都留有一些未用的字节。留有多少字节应看系统要在多大程度上避免内存碎片。对小型系统来说,增加几个字节的内部碎片是朝正确方向迈出的一步。当系统请求1字节内存时,你分配的存储量取决于系统的工作状态。 如果系统分配的内存存储量的主要部分是 1 ~ 16 字节,则为小内存也分配 16 字节是明智的。只要限制可以分配的最大内存块,你就能够获得较大的节约效果。但是,这种方法的缺点是,系统会不断地尝试分配大于极限的内存块,这使系统可能会停止工作。减少最大和最小内存块存储量之间内存存储量的数量也是有用的。采用按对数增大的内存块存储量可以避免大量的碎片。例如,每个存储量可能都比前一个存储量大 20%。在嵌入式系统中采用“一种存储量符合所有需要”对于嵌入式系统中的内存分配程序来说可能是不切实际的。这种方法从内部碎片来看是代价极高的,但系统可以彻底避免外部碎片,达到支持的最大存储量。 将相邻空闲内存块连接起来是一种可以显着减少内存碎片的技术。如果没有这一方法,某些分配算法(如最先适合算法)将根本无法工作。然而,效果是有限的,将邻近内存块连接起来只能缓解由于分配算法引起的问题,而无法解决根本问题。而且,当内存块存储量有限时,相邻内存块连接可能很难实现。 有些内存分配器很先进,可以在运行时收集有关某个系统的分配习惯的统计数据,然后,按存储量将所有的内存分配进行分类,例如分为小、中和大三类。系统将每次分配指向被管理内存的一个区域,因为该区域包括这样的内存块存储量。较小存储量是根据较大存储量分配的。这种方案是最先适合算法和一组有限的固定存储量算法的一种有趣的混合,但不是实时的。 有效地利用暂时的局限性通常是很困难的,但值得一提的是,在内存中暂时扩展共处一地的分配程序更容易产生内存碎片。尽管其它技术可以减轻这一问题,但限制不同存储量内存块的数目仍是减少内存碎片的主要方法。 现代软件环境业已实现各种避免内存碎片的工具。例如,专为分布式高可用性容错系统开发的 OSE 实时操作系统可提供三种运行时内存分配程序:内核 alloc(),它根据系统或内存块池来分配;堆 malloc(),根据程序堆来分配; OSE 内存管理程序 alloc_region,它根据内存管理程序内存来分配。 从 许多方面来看,Alloc就是终极内存分配程序。它产生的内存碎片很少,速度很快,并有判定功能。你可以调整甚至去掉内存碎片。只是在分配一个存储量后,使之空闲,但不再分配时,才会产生外部碎片。内部碎片会不断产生,但对某个给定的系统和八种存储量来说是恒定不变的。 Alloc 是一种有八个自由表的固定存储量内存分配程序的实现方法。系统程序员可以对每一种存储量进行配置,并可决定采用更少的存储量来进一步减少碎片。除开始时以外,分配内存块和使内存块空闲都是恒定时间操作。首先,系统必须对请求的存储量四舍五入到下一个可用存储量。就八种存储量而言,这一目标可用三个 如果 语句来实现。其次,系统总是在八个自由表的表头插入或删除内存块。开始时,分配未使用的内存要多花几个周期的时间,但速度仍然极快,而且所花时间恒定不变。 堆malloc() 的内存开销(8 ~ 16 字节/分配)比 alloc小,所以你可以停用内存的专用权。malloc() 分配程序平均来讲是相当快的。它的内部碎片比alloc()少,但外部碎片则比alloc()多。它有一个最大分配存储量,但对大多数系统来说,这一极限值足够大。可选的共享所有权与低开销使 malloc() 适用于有许多小型对象和共享对象的 C++ 应用程序。堆是一种具有内部堆数据结构的伙伴系统的实现方法。在 OSE 中,有 28 个不同的存储量可供使用,每种存储量都是前两种存储量之和,于是形成一个斐波那契(Fibonacci)序列。实际内存块存储量为序列数乘以 16 字节,其中包括分配程序开销或者 8 字节/分配(在文件和行信息启用的情况下为 16 字节)。 当你很少需要大块内存时,则OSE内存管理程序最适用。典型的系统要把存储空间分配给整个系统、堆或库。在有 MMU 的系统中,有些实现方法使用 MMU 的转换功能来显着降低甚至消除内存碎片。在其他情况下,OSE 内存管理程序会产生非常多的碎片。它没有最大分配存储量,而且是一种最先适合内存分配程序的实现方法。内存分配被四舍五入到页面的偶数——典型值是 4 k 字节。(T111)

3. TIFF、JPEG、CGM、EMF、PNG分别是什么格式的文件

常见的扩展名】我就略说些经常遇到的,但并不是人人都认识的扩展名:
〔*.exe‖可执行文件;直接打开〕
〔*.rar‖一种压缩包;用WinRAR打开〕
〔*.zip‖一种压缩包;用WinRAR打开,或者WinXP也可以直接打开〕
〔*.iso‖虚拟光驱;用WinRAR打开,也可用其他虚拟光驱软件〕
〔*.doc‖word文档;用Office Word打开〕
〔*.ppt‖幻灯片; 用Office PowerPiont打开〕
〔*.xls‖电子表格;用Office Excel打开〕
〔*.wps‖WPS文档; 用金山WPS打开〕
〔*.txt‖文本文档;默认用记事本打开〕
〔*.lrc‖动态歌词;可以用记事本打开〕
〔*.rm,*.rmvb‖高清视频;可以用RealOnePlayer打开〕
〔*.mp3,*.wma,*.wav‖一些音乐〕
〔*.jpg,*.bmp,*.gif‖一些图片,其中gif可以是动态的〕
〔*.wfs‖Flash文件;可以用IE打开,也可用FlashPlayer打开〕
〔*.torrent‖BT文件;可以用BitComet打开〕

A
ACE:Ace压缩档案格式
ACT:Microsoft office助手文件
AIF,AIFF:音频互交换文件,Silicon Graphic and Macintosh应用程序的声音格式
ANI:Windows系统中的动画光标
ARC:LH ARC的压缩档案文件
ARJ:Robert Jung ARJ压缩包文件
ASD:Microsoft Word的自动保存文件;Microsoft高级流媒体格式(microsoft advanced streaming
format,ASF)的描述文件;可用NSREX打开 Velvet Studio例子文件
ASF:Microsoft高级流媒体格式文件
ASM:汇编语言源文件,Pro/E装配文件
ASP:动态网页文件;ProComm Plus安装与连接脚本文件;Astound介绍文件
AST:Astound多媒体文件;ClarisWorks“助手”文件
Axx:ARJ压缩文件的分包序号文件,用于将一个大文件压至几个小的压缩包中(xx取01-99的数字)
A3L:Authorware 3.x库文件
A4L:Authorware 4.x库文件
A5L:Authorware 5.x库文件
A3M,A4M:Authorware Macintosh未打包文件
A3W,A4W,A5W:未打包的Authorware Windows文件
B
BAK:备份文件
BAS:BASIC源文件
BAT:批处理文件
BIN:二进制文件
BINHex:苹果的一种编码格式
BMP:Windows或OS/2位图文件
BOOK:Adobe FrameMaker Book文件
BOX:Lotus Notes的邮箱文件
BPL:Borlard Delph 4打包库
BSP:Quake图形文件
BUN:CakeWalk 声音捆绑文件(一种MIDI程序)
C
C0l:台风波形文件
CAB:Microsoft压缩档案文件
CAD:Softdek的Drafix CAD文件
CAM:Casio照相机格式
CAP:压缩音乐文件格式
CAS:逗号分开的ASCⅡ文件
CCB:Visual Basic动态按钮配置文件
CCH:Corel图表文件
CCO:CyberChat数据文件
CCT:Macromedia Director Shockwave投影
CDA:CD音频轨道
CDF:Microsoft频道定义格式文件
CDI:Philip的高密盘交互格式
CDM:Visual dBASE自定义数据模块文件
CDR:CorelDRAW绘图文件;原始音频CD数据文件
CDT:CorelDRAW模板
CDX:CorelDRAW压缩绘图文件;Microsoft Visual FoxPro索引文件
CFG:配置文件
CGI:公共网关接口脚本文件
CGM:计算机图形元文件
CH:OS/2配置文件
CHK:由Windows磁盘碎片整理器或磁盘扫描保存的文件碎片
CHM:编译过的HTML文件
CHP:Ventura Publisher章节文件
CHR:字符集(字体文件)
CHT:ChartViem文件;Harvard Graphics矢量文件
CIF:Adaptec CD 创建器 CD映像文件
CIL:Clip Gallery下载包
CIM:SimCity 2000文件
CIN:OS/2改变控制文件用于跟踪INI文件中的变化
CLASS:Java类文件
CLP:Windows 剪贴板文件
CLL:Crick Software Clicker文件
CLS:Visual Basic类文件
CMD:Windows NT,OS/2的命令文件;DOS CD/M命令文件;dBASEⅡ程序文件
CPI:Microsoft MS-DOS代码页信息文件
CPL:控制面板扩展名,Corel颜色板
CPP:C++代码文件
CPR:Corel提供说明书文件
CPT:Corel 照片-绘画图像
CST:Macromedia Director Cast文件
CUR:Windows光标文件
D
DBF:dBASE文件,一种由Ashton-Tate创建的格式,可以被ACT!、Lipper、FoxPro、Arago、Wordtech、Xbase和类似数据库或与数据库有关产品识别;可用数据文件(能被Excel
97打开);Oracle 8.1.x表格空间文件
DBX:DataBearn图像;Microsoft Visual FoxPro表格文件
DCT:Microsoft Visual FoxPro数据库容器
DCU:Delphi编译单元文件
DCX:Microsoft Visual FoxPro数据库容器;基于PCX的传真图像;宏
DIR:MacromediaDirector文件
DLL:动态链接库
DOC:FrameMaker或FrameBuilder文档;Word Star文档、Word
Perfect文档、Microsoft:Word文档;DisplayWrite文档
DOT:Microsoft Word文档模板
DPL:Borland Delph 3压缩库
DRV:驱动程序
DRW:Micrografx Designer/Draw;Pro/E绘画文件
DSF:Micrografx Designer VFX文件
DSG:DOOM保存的文件
DSM:Dynamic Studio音乐模块(MOD)文件
DSP:Microsoft Developer Studio工程文件
DSQ:Corel QUERY(查询)文件
DST:刺绣机图形文件
DSW:Microsoft Developer Studio工作区文件
DTA:World Bank(世界银行)的STARS数据文件
DTD:SGML文档类型定义(DTD)文件
DTED:地面高度数字数据(图形的数据格式)文件
DTF:Symantec Q&A相关的数据库数据文件
DTM:DigiTrakker模块文件
DUN:Microsoft拔号网络导出文件
DV:数字视频文件(MIME)
DWG:AutoCAD工程图文件;AutoCAD或Generic CADD老版本的绘图格式
DXR:Macromedia Director受保护(不可编辑)电影文件
E
EDA:Ensoniq ASR磁盘映像
EDD:元素定义文档(FrameMaker+SGML文档)
EDE:Ensoniq EPS磁盘映像
EDK:Ensoniq KT磁盘映像
EDQ:Ensoniq SQ1/SQ2/Ks32磁盘映像
EDS:Ensoniq SQ80磁盘映像
EDV:Ensoniq VFX-SD磁盘映像
EFA:Ensoniq ASR文件
EFE:Ensoniq EPS文件
EFK:Ensoniq KT文件
EFQ:Ensoniq SQ1/SQ2/Ks32文件
EFS:Ensoniq SQ80文件
EFV:Ensoniq VFX-SD文件
EMD:ABT扩展模块
EMF:Windows增强元文件
EML:Microsoft Outlook Express邮件消息(MIME RTC822)文件
EXE:可执行文件(程序)
F
FAV:Microsoft Outlook导航条
FAX:传真类型图像
FCD:虚拟CD-ROM
FDF:Adobe Acrobat表单文档文件
FLA:Macromedia Flash电影
FND:Microsoft Explorer保存的搜索文件(Find applet)
FON:系统字体
FRT:Microsoft FoxPro报表文件
FRX:Visual Basic表单文本;Microsoft FoxPro报表文件
FXP:经Microsoft FoxPro编译的源文件
G
GDM:铃声、口哨声和声音板模块格式
GetRight:GetRight未完成的下载文件
GHO:Norton 克隆磁盘映像
GID:Windows 95全局索引文件(包括帮助状态)
GIF:CompuServe位图文件
GL:动画格式
GRP:程序管理组
H
HEX:Macintosh BinHex2.0文件
HLP:帮助文件;Date CAD Windows帮助文件
HPP:C++程序头文件
HQX:Macintosh BinHex 4.0文件
HT:HyperTerminal(超级终端)
HTM,HTML:超文本文档
HTT:Microsoft超文本模板
HTX:扩展HTML模板
I
ICO:Windows图标
IDX:Microsoft FoxPro相关数据库索引文件;Symantec Q&A相关数据库索引文件;Microsoft Outlook
Express文件
IMG:GEM映像
INF:信息文件
INI:初始化文件;Mwave DSP Synth的“nwsynth.ini” GMS安装;Cravis Ultrasound bank安装
INP:Oracle 3.0版或早期版本的表单源代码
INRS:INRS远程通信声频
INS:InstallShield安装脚本;X-Internet签字文件;Ensoniq EPS字簇设备;Cell/ⅡMAC/PC抽样设备
INT:中间代码,当一个源程序经过语法检查后编译产生一个可执行代码
IOF:Findit文档
IQY:Microsoft Internet查询文件
ISO:根据ISD 9660有关CD-ROM文件系统标准列出CD-ROM上的文件
ISP:X-Internet签字文件
IST:数字跟踪设备文件
ISU:InstallShield卸装脚本
IT:脉冲跟踪系统音乐模块(MOD)文件
ITI:脉冲跟踪系统设备
ITS:脉冲跟踪系统抽样,Internet文档位置
IV:Open Inventor中使用的文件格式
IVD:超过20/20微观数据维数或变量等级文件
IVP:超过20/20的用户子集配置文件
IVT:超过20/20表或集合数据文件
IVX:超过20/20微数据目录文件
IW:Idlewild屏幕保护程序
IWC:Install Watch文档
J
J62:Ricoh照相机格式
JAR:Java档案文件(一种用于applet和相关文件的压缩文件)
JAVA:Java源文件
JAR:Java档案文件(一种用于applet和相关文件的压缩文件)
JAVA:Java源文件
JFF,JFIF,JIF:JPEG文件
JPE,JPEG,JPG:JPEG图形文件
JS:JavaScript源文件
JSP:HTML网页,其中包含有对一个Java servlet的参考
K
KAR:卡拉OK MIDI文件(文本+MIDI)
L
LAB:Visual dBASE标签文件
LBT,LBX:Microsoft FoxPro标签文件
LDB:Microsoft Access加锁文件
LHA:LZH更换文件后缀
LOG:日志文件
LZH:LH ARC压缩档案
M
M1V:MPEG相关文件(MIME"mpeg"类型)
M3D:Corel Motion 3D动画文件
M3U:MPEG URL(MIME声音文件)
MAM:Microsoft Access宏
MAQ:Microsoft Access查询文件
MAR:Microsoft Access报表文件
MBX:Microsoft Outlook保存email格式;Eudora邮箱
MCW:Microsoft Word的Macintosh文档
MDB:Microsoft Access数据库
MDN:Microsoft Access空数据库模板
MDW:Microsoft Access工作组文件
MID:MIDI音乐
MMM:Microsoft多媒体电影
MOV:QuickTime for Windows电影
MP2:第二层MPEG音频文件
MP3:第三层MPEG音频文件
MPA:MPEG相关文件,MIME“mpeg类型”
MPE,MPEG,MPG:MPEG动画文件
MPP:Microsoft工程文件;CAD绘图文件格式
MPR:Microsoft FoxPro菜单(已编译)
MSI:Windows 安装器包
MSN:Microsoft 网络文档;Descent Mission文件
O
OBD:Microsoft Office活页夹
OBJ:对象文件
OBZ:Microsoft Office活页夹向导
OCX:Microsoft对象链接与嵌入定制控件
ODS:Microsoft Outlook Express邮箱文件
OFT:Microsoft Outlook模板
OPX:OPL扩展DLL(动态链接库)
OSS:Microsoft Office查找文件
OST:Microsoft Exchange / Outlook 离线文件
P
PAL:压缩文件
PART:Go!Zilla部分下载文件
PAS:Pascal源代码
PCS:PICS动画文件
PDF:Adobe Acrobat
可导出文档格式文件(可用Web浏览器显示);Microsoft系统管理服务器包定义文件;NetWare打印机定义文件
PHP,PHP3:包含有PHP脚本的HTML网页
PHTML:包含有PHP脚本的HTML网页;由Perl分析解释的HTML
PM5:Pagemaker 5.0文件
PM6:Pagemaker 6.0文件
PPS:Microsoft Powerpoint幻灯片放映
PPT:Microsoft Powerpoint演示文稿
PRF:Windows系统文件,Macromedia导演设置文件
PSD:Adobe photoshop位图文件
PSM:Protracker Studio模型格式;Epic游戏的源数据文件
PST:Microsoft Outlook个人文件夹文件
PWL:Windows 95口令列表文件
Q
QIF:QuickTime相关图像(MIME);Quicken导入文件
QT,QTM:QuickTime电影
QTI,QTIF:QuickTime相关图像
QTP:QuickTime优先文件
QTS:Mac PICT图像文件;QuickTime相关图像
QTX:QuickTime相关图像
R
RA:RealAudio声音文件
RAM:RealAudio元文件
RAR:RAR压缩档案(Eugene Roshall格式)
REC:录音机宏;RapidComm声音文件
REG:注册表文件
REP:Visual dBASE报表文件
RES:Microsoft Visual C++资源文件
RM:RealAudio视频文件
RMF:Rich Map格式(3D游戏编辑器使用它来保存图)
ROM:基于盒式磁带的家庭游戏仿真器文件(来自Atari
2600、Colecovision、Sega、Nintendo等盒式磁带里的ROM完全拷贝,在两个仿真器之间不可互修改)
Rxx:多卷档案上的RAR压缩文件(xx=1~99间的一个数字)
S
SAV:游戏保存文件
SB:原始带符号字节(8位)数据
SBK:Creative Labs的Soundfont 1.0 Bank文件;(Soundb laster)/EMU SonndFont v1.x
Bank文件
SBL:Shockwave Flash对象文件
SCF:Windows Explorer命令文件
SCH:Microsoft Schele+1
SCP:拨号网络脚本文件
SCR:Windows屏幕保护;传真图像;脚本文件
SFX:RAR自解压档案
SHTML:含有服务器端包括(SSI)的HTML文件
SPL:Shockwave Flash对象;DigiTrakker抽样
SQL:Informix SQL查询;通常被数据库产品用于SQL查询(脚本、文本、二进制)的文件扩展名
STM:.shtml的短后缀形式,含有一个服务端包括(SSI)的HTML文件;Scream Tracker V2音乐模块(MOD)文件
STR:屏幕保护文件
SWA:在Macromedia导演文件(MP3文件)中的Shockwave声音文件
SWF:Shockwave Flash对象
SYS:系统文件
T
T64:Commodore 64仿真器磁带映像文件
THEME:Windows 95桌面主题文件
TIF,TIFF:标签图像文件格式(TIFF)位图
TMP:Windows临时文件
TRM:终端文件
TXT:ASCⅡ文本格式的声音数据
TZ:老的压缩格式文件
V
VBA:VBase文件
VBP:Microsoft Visual Basic工程文件
VBW:Microsoft Visual Basic工作区文件
VBX:Microsoft Visual Basic用户定制控件
VQE,VQL:Yamaha Sound-VQ定位器文件
VQF:Yamaha Sound-VQ文件(可能出现标准)
VRF:Oracle 7配置文件
VSL:下载列表文件(GetRight)
W
WAB:Microsoft Outlook文件
WAD:包含有视频、玩家水平和其他信息的DOOM游戏的大文件
WAL:Quake 2正文文件
WAV:Windows波形声形
WBK:Microsoft Word备份文件
WFM:Visual dBASE Windows表单
WFN:在CorelDRAW中使用的符号
WIZ:Microsoft Word向导
WRL:虚拟现实模型
WWL:Microsoft Word内插器文件
X
XLK:Microsoft Excel备份
XLL:Microsoft Excel内插器文件
XLM:Microsoft Excel宏
XLS:Microsoft Excel工作单
XLT:Microsoft Excel模板
XLV:Microsoft Excel VBA模块
XLW:Microsoft Excel工作簿/工作区
Z
ZAP:Windows软件安装配置文件
ZIP:Zip文件

4. 为什么有些软件一定要装在C盘(系统盘)才能使用

主要是系统的设计需要,还有就是有些软件的设定不支持c盘以外的盘符。

一个原因是因为要尊重系统的设计,Windows系统中: Program Files和Program Files(x86)是用来存放程序本体的, ProgramData和%user%/appdata是用来存放程序数据的,当你的程序本体出现问题, 你只需要重新安装程序, 你的用户数据依然会保存。

当你要还原程序设置,你只需要从ProgramData或者%user%/appdata中删掉程序的配置文件,就能够把程序还原到初始设置程序在安装过程中向对应的注册表位置写入软件信息和卸载程序的路径,这样就可以通过控制面板统一的管理程序。

还有一个原因是软件如果支持C盘以外的盘符,需要额外的编码以及额外的测试。如果产品经理与测试工程师都没有对只能装C盘表示异议,那么程序员当然只需要实现C盘安装的功能。所以有的软件是不支持c盘以外的盘符的。

(4)程序员的文件碎片扩展阅读:

软件装在c盘的优缺点。

软件装在C盘的读取速度更快。相较于C盘后面的D盘、E盘之类的,C盘是开机最先读取的,速度也是最快的,因为C盘是系统盘,软件和系统盘安装在一起,可以减少运行时间。

是这些软件的运行会使C分区生成一些缓存文件碎片,随着这些文件的增多,会拖慢系统运行速度。

众多软件同系统文件混杂在一起,不便于管理维护。

5. 操作系统执行可执行程序时,内存分配是怎样的

在操作系统中,一个进程就是处于执行期的程序(当然包括系统资源),实际上正在执行的程序代码的活标本。那么进程的逻辑地址空间是如何划分的呢?

图1做了简单的说明(Linux系统下的):

图一

左边的是UNIX/LINUX系统的执行文件,右边是对应进程逻辑地址空间的划分情况。

一般认为在c中分为这几个存储区: 1. 栈 --有编译器自动分配释放 2. 堆 -- 一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收 3. 全局区(静态区) -- 全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。程序结束释放。 4. 另外还有一个专门放常量的地方。程序结束释放。 在函数体中定义的变量通常是在栈上,用malloc, calloc, realloc等分配内存的函数分配得到的就是在堆上。在所有函数体外定义的是全局量,加了static修饰符后不管在哪里都存放在全局区(静态区),在所有函数体外定义的static变量表示在该文件中有效,不能extern到别的文件用,在函数体内定义的static表示只在该函数体内有效。另外,函数中的"adgfdf"这样的字符串存放在常量区。比如:代码:

int a = 0; //全局初始化区

char *p1; //全局未初始化区

main(){

int b; //栈

char s[] = "abc"; //栈

char *p2; //栈

char *p3 = "123456"; //123456在常量区,p3在栈上。

static int c = 0; //全局(静态)初始化区

p1 = (char *)malloc(10);

p2 = (char *)malloc(20);//分配得来得10和20字节的区域就在堆区。

strcpy(p1, "123456");//123456放在常量区,编译器可能会将它与p3所指向 的"123456"优化成一块。

}

还有就是函数调用时会在栈上有一系列的保留现场及传递参数的操作。 栈的空间大小有限定,vc的缺省是2M。栈不够用的情况一般是程序中分配了大量数组和递归函数层次太深。有一点必须知道,当一个函数调用完返回后它会释放该函数中所有的栈空间。栈是由编译器自动管理的,不用你操心。 堆是动态分配内存的,并且你可以分配使用很大的内存。但是用不好会产生内存泄漏。并且频繁地malloc和free会产生内存碎片(有点类似磁盘碎片),因为c分配动态内存时是寻找匹配的内存的。而用栈则不会产生碎片。 在栈上存取数据比通过指针在堆上存取数据快些。 一般大家说的堆栈和栈是一样的,就是栈(stack),而说堆时才是堆heap. 栈是先入后出的,一般是由高地址向低地址生长。

堆(heap)和堆栈(stack)的区别

2.1申请方式stack:由系统自动分配。 例如,声明在函数中一个局部变量 int b; 系统自动在栈中为b开辟空间heap:需要程序员自己申请,并指明大小,在c中malloc函数

如p1 = (char *)malloc(10);

在C++中用new运算符

如p2 = (char *)malloc(10);

但是注意p1、p2本身是在栈中的。

2.2 申请后系统的响应栈:只要栈的剩余空间大于所申请空间,系统将为程序提供内存,否则将报异常提示栈溢出。堆:首先应该知道操作系统有一个记录空闲内存地址的链表,当系统收到程序的申请时,会遍历该链表,寻找第一个空间大于所申请空间的堆结点,然后将该结点从空闲结点链表中删除,并将该结点的空间分配给程序,另外,对于大多数系统,会在这块内存空间中的首地址处记录本次分配的大小,这样,代码中的delete语句才能正确的释放本内存空间。另外,由于找到的堆结点的大小不一定正好等于申请的大小,系统会自动的将多余的那部分重新放入空闲链表中。

2.3

2.4申请效率的比较:栈由系统自动分配,速度较快。但程序员是无法控制的。堆是由new分配的内存,一般速度比较慢,而且容易产生内存碎片,不过用起来最方便.另外,在WINDOWS下,最好的方式是用VirtualAlloc分配内存,他不是在堆,也不是在栈是直接在进程的地址空间中保留一快内存,虽然用起来最不方便。但是速度快,也最灵活。

2.5堆和栈中的存储内容栈: 在函数调用时,第一个进栈的是主函数中后的下一条指令(函数调用语句的下一条可执行语句)的地址,然后是函数的各个参数,在大多数的C编译器中,参数是由右往左入栈的,然后是函数中的局部变量。注意静态变量是不入栈的。当本次函数调用结束后,局部变量先出栈,然后是参数,最后栈顶指针指向最开始存的地址,也就是主函数中的下一条指令,程序由该点继续运行。堆:一般是在堆的头部用一个字节存放堆的大小。堆中的具体内容有程序员安排。

2.6存取效率的比较

char s1[] = "aaaaaaaaaaaaaaa";

char *s2 = "bbbbbbbbbbbbbbbbb";

aaaaaaaaaaa是在运行时刻赋值的;

而bbbbbbbbbbb是在编译时就确定的;

但是,在以后的存取中,在栈上的数组比指针所指向的字符串(例如堆)快。

比如:#include <...>

void main(){

char a = 1;

char c[] = "1234567890";

char *p ="1234567890";

a = c[1];

a = p[1];

return;

}

对应的汇编代码

10: a = c[1];

00401067 8A 4D F1 mov cl,byte ptr [ebp-0Fh]

0040106A 88 4D FC mov byte ptr [ebp-4],cl

11: a = p[1];

0040106D 8B 55 EC mov edx,dword ptr [ebp-14h]

00401070 8A 42 01 mov al,byte ptr [edx+1]

00401073 88 45 FC mov byte ptr [ebp-4],al

第一种在读取时直接就把字符串中的元素读到寄存器cl中,而第二种则要先把指针值读到edx中,在根据edx读取字符,显然慢了。

2.7小结:堆和栈的区别可以用如下的比喻来看出:使用栈就象我们去饭馆里吃饭,只管点菜(发出申请)、付钱、和吃(使用),吃饱了就走,不必理会切菜、洗菜等准备工作和洗碗、刷锅等扫尾工作,他的好处是快捷,但是自由度小。使用堆就象是自己动手做喜欢吃的菜肴,比较麻烦,但是比较符合自己的口味,而且自由度大。堆和栈的区别主要分:操作系统方面的堆和栈,如上面说的那些,不多说了。还有就是数据结构方面的堆和栈,这些都是不同的概念。这里的堆实际上指的就是(满足堆性质的)优先队列的一种数据结构,第1个元素有最高的优先权;栈实际上就是满足先进后出的性质的数学或数据结构。虽然堆栈,堆栈的说法是连起来叫,但是他们还是有很大区别的,连着叫只是由于历史的原因。

申请大小的限制栈:在Windows下,栈是向低地址扩展的数据结构,是一块连续的内存的区域。这句话的意思是栈顶的地址和栈的最大容量是系统预先规定好的,在 WINDOWS下,栈的大小是2M(也有的说是1M,总之是一个编译时就确定的常数),如果申请的空间超过栈的剩余空间时,将提示overflow。因此,能从栈获得的空间较小。堆:堆是向高地址扩展的数据结构,是不连续的内存区域。这是由于系统是用链表来存储的空闲内存地址的,自然是不连续的,而链表的遍历方向是由低地址向高地址。堆的大小受限于计算机系统中有效的虚拟内存。由此可见,堆获得的空间比较灵活,也比较大。一、预备知识—程序的内存分配一个由c/C++编译的程序占用的内存分为以下几个部分

1、栈区(stack)— 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。2、堆区(heap)— 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表,呵呵。3、全局区(静态区)(static)—全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域, 未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。 - 程序结束后有系统释放4、文字常量区 —常量字符串就是放在这里的。 程序结束后由系统释放5、程序代码区(text)—存放函数体的二进制代码。

6. C++中 关于内存碎片的,为什么要重载new和delete,这跟系统内置的new和delete有什么不同(关于内存的)

首先看碎片,32位系统的内存是按“页”管理的,一页内存为64K,只有当前在使用的页面才会在内存中,其他页面不一定总是在内存。因此,分配连续的内存时,当请求少于64K,系统会尽量将其分配在一个内存页面中,当大于64K时,会分配在连续的页面中。以实例说明,例如首先请求30K内存,那么会在第一页分配,第二次请求50K,就必须在第二页面分配。于是第一次返回的地址为0,第二次为64K,30K~64K之间的内存就是所谓的“碎片”。可以将“碎片”简单理解为两块以分配内存之间的空间。当然,“碎片”也可能被利用,但是考虑一种极端的情况:如果一台电脑拥有4G内存,但是每个页面都只分配了32K,那么你将不能申请一片大于32K的内存,即使目前你的物理内存还有2G没有使用。这种情况是很常见的,当程序比较大时如果你没作好这些管理,你会发现new个3~5百MB内存会经常失败。
系统中的new会实施一些算法或者策略,防止内存碎片过快产生,这些算法类似于数据结构中的“堆”,所以new被称之为“堆分配”。但是,系统的堆管理策略是宏观的,通用的。你只要使用它,一定会产生内存碎片。同时,随着堆的规模的加大,会有很多时间浪费在页面在主存与虚拟内存的交换中,这是因为一般情况下,系统返回给你的内存指针是不能改变的,试想你的程序中new了一个新指针,可这片内存不知什么时候被系统换到其他地方了,那么你的程序离奔溃就不远了。这说明在C++中,出现内存碎片后系统是无法执行“碎片整理”的,然而在底层的windows接口中,你能使用“内存句柄”代替指针,内存句柄代表的内存是操作系统管理的而不是地址本身,因此这种情况下操作系统能帮你完成“碎片整理”。只是,内存句柄即使在微软自己的平台上也不及指针通用,各种内库的接口中,绝大部分只认指针,因此你可能在“内存句柄”与指针间不停转换消耗掉程序的时间。
重写内存管理要根据实际需要,这没有统一的方法。最简单的做法是让new返回一个全局数组的地址。全局数组的内存空间在程序启动时就初始化好了,因此你立即就能获取到地址并且这个分配一定是成功的(要是内存耗尽,程序会在启动时挂掉)。全局数组好处在于它的内存一定是连续的,32位系统上能保证2G左右的长度,因此对于操作系统而言可以做到消除碎片,至于如何高效使用这些内存就是程序员的事情了。最后,全局数组的方法也要注意64K对其,否则程序性能会因为内存交换收到影响,特别是当内存使用量很大的时候。
最后,除非程序需要极高的性能,比如大型三维游戏;或者你的程序特别吃内存,比如服务器上的某些服务。你是完没必要重写new delete。

7. 程序员如何清理电脑垃圾

在网络飞速发展的现在,如今电脑已经成为了人们生活中不可或缺的一件物品了。不管是办公还是娱乐,电脑都是很多人的第一选择。但电脑在带给人们方便的同时,也会让它自己积攒很多的无效文件,也就是大家熟知的电脑垃圾,当电脑垃圾积累到一定程度的时候就需要清理一下了。你一般是怎么清理电脑垃圾的呢?今天小编就带大家来看看,普通人清理电脑垃圾和程序员清理电脑垃圾的区别吧。

电脑在运行过程中,会产生很多系统垃圾,占用硬盘资源,垃圾多了会拖慢系统响应速度,这个时候就需要清理一下了,而很多人是不是直接下载一个电脑垃圾清理软件,直接点击一键清理来清理电脑的垃圾的?尽管这样是很简单方便,虽然借助卫士或者杀软,也能清理电脑垃圾,但它需要经常检测电脑的情况,会需要时时刻刻监测电脑的情况,所以会占用很大的电脑资源,如果你电脑的运行内存只有4个G的话,那使用这个反而可能会拖累电脑,使之变的更慢,还不如不用。

那有人就会说了,我可以在需要清理的时候再去下载工具,清理完了之后再卸载它,但这样是不是太过麻烦了。其实清理电脑垃圾对于程序员来说就是小事一桩,所以这就是程序员和不懂电脑的小白之间的区别,今天小编就安利一个程序员清理电脑垃圾的方法,既不占用系统资源又能有效的清理电脑垃圾。

好了,闲话不多说,我们开始教学吧,第一步:右击桌面空白处,新建一个文本文档.txt文件。

第二步,打开新建文本文档.txt文件,将下面的代码复制粘贴到里面,并保存退出。

8. 程序员必备知识(操作系统5-文件系统)

本篇与之前的第三篇的内存管理知识点有相似的地方

对于运行的进程来说,内存就像一个纸箱子, 仅仅是一个暂存数据的地方, 而且空间有限。如果我们想要进程结束之后,数据依然能够保存下来,就不能只保存在内存里,而是应该保存在 外部存储 中。就像图书馆这种地方,不仅空间大,而且能够永久保存。

我们最常用的外部存储就是 硬盘 ,数据是以文件的形式保存在硬盘上的。为了管理这些文件,我们在规划文件系统的时候,需要考虑到以下几点。

第一点,文件系统要有严格的组织形式,使得文件能够 以块为单位进行存储 。这就像图书馆里,我们会给设置一排排书架,然后再把书架分成一个个小格子,有的项目存放的资料非常多,一个格子放不下,就需要多个格子来进行存放。我们把这个区域称为存放原始资料的 仓库区 。

第二点,文件系统中也要有 索引区 ,用来方便查找一个文件分成的多个块都存放在了什么位置。这就好比,图书馆的书太多了,为了方便查找,我们需要专门设置一排书架,这里面会写清楚整个档案库有哪些资料,资料在哪个架子的哪个格子上。这样找资料的时候就不用跑遍整个档案库,在这个书架上找到后,直奔目标书架就可以了。

第三点,如果文件系统中有的文件是热点文件,近期经常被读取和写入,文件系统应该有 缓存层 。这就相当于图书馆里面的热门图书区,这里面的书都是畅销书或者是常常被借还的图书。因为借还的次数比较多,那就没必要每次有人还了之后,还放回遥远的货架,我们可以专门开辟一个区域, 放置这些借还频次高的图书。这样借还的效率就会提高。

第四点,文件应该用 文件夹 的形式组织起来,方便管理和查询。这就像在图书馆里面,你可以给这些资料分门别类,比如分成计算机类.文学类.历史类等等。这样你也容易管理,项目组借阅的时候只要在某个类别中去找就可以了。

在文件系统中,每个文件都有一个名字,这样我们访问一个文件,希望通过它的名字就可以找到。文件名就是一个普通的文本。 当然文件名会经常冲突,不同用户取相同的名字的情况还是会经常出现的。

要想把很多的文件有序地组织起来,我们就需要把它们成为 目录 或者文件夹。这样,一个文件夹里可以包含文件夹,也可以包含文件,这样就形成了一种 树形结构 。而我们可以将不同的用户放在不同的用户目录下,就可以一定程度上避免了命名的冲突问题。

第五点,Linux 内核要在自己的内存里面维护一套数据结构,来保存哪些文件被哪些进程打开和使用 。这就好比,图书馆里会有个图书管理系统,记录哪些书被借阅了,被谁借阅了,借阅了多久,什么时候归还。

文件系统是操作系统中负责管理持久数据的子系统,说简单点,就是负责把用户的文件存到磁盘硬件中,因为即使计算机断电了,磁盘里的数据并不会丢失,所以可以持久化的保存文件。

文件系统的基本数据单位是 文件 ,它的目的是对磁盘上的文件进行组织管理,那组织的方式不同,就会形成不同的文件系统。

Linux最经典的一句话是:“一切皆文件”,不仅普通的文件和目录,就连块设备、管道、socket 等,也都是统一交给文件系统管理的。

Linux文件系统会为每个文件分配两个数据结构: 索引节点(index node) 和 目录项(directory entry) ,它们主要用来记录文件的元信息和目录层次结构。

●索引节点,也就是inode, 用来记录文件的元信息,比如inode编号、文件大小访问权限、创建时间、修改时间、 数据在磁盘的位置 等等。 索引节点是文件的唯一标识 ,它们之间一一对应, 也同样都会被 存储在硬盘 中,所以索引节点同样占用磁盘空间。

●目录项,也就是dentry, 用来记录文件的名字、索引节点指针以及与其他目录项的层级关联关系。多个目录项关联起来,就会形成 目录结构 ,但它与索引节点不同的是,目录项是由内核维护的一个数据结构,不存放于磁盘,而是 缓存在内存 。

由于索引节点唯一标识一个文件,而目录项记录着文件的名,所以目录项和索引节点的关系是多对一,也就是说,一个文件可以有多个别字。比如,硬链接的实现就是多个目录项中的索引节点指向同一个文件。

注意,目录也是文件,也是用索引节点唯一标识,和普通文件不同的是,普通文件在磁盘里面保存的是文件数据,而目录文件在磁盘里面保存子目录或文件。

(PS:目录项和目录不是一个东西!你也不是一个东西(^_=), 虽然名字很相近,但目录是个文件。持久化存储在磁盘,而目录项是内核一个数据结构,缓存在内存。

如果查询目录频繁从磁盘读,效率会很低,所以内核会把已经读过的目录用目录项这个数据结构缓存在内存,下次再次读到相同的目录时,只需从内存读就可以,大大提高了 文件系统的效率。

目录项这个数据结构不只是表示目录,也是可以表示文件的。)

磁盘读写的最小单位是 扇区 ,扇区的大小只有512B大小,很明显,如果每次读写都以这么小为单位,那这读写的效率会非常低。

所以,文件系统把多个扇区组成了一个 逻辑块 ,每次读写的最小单位就是逻辑块(数据块) , Linux中的逻辑块大小为4KB,也就是一次性读写 8个扇区,这将大大提高了磁盘的读写的效率。

以上就是索引节点、目录项以及文件数据的关系,下面这个图就很好的展示了它们之间的关系:

索引节点是存储在硬盘上的数据,那么为了加速文件的访问,通常会把索引节点加载到内存中。

另外,磁盘进行格式化的时候,会被分成三个存储区域,分别是超级块、索引节点区和数据块区。

●超级块,用来存储文件系统的详细信息,比如块个数、块大小、空闲块等等。

●索引节点区,用来存储索引节点;

●数据块区,用来存储文件或目录数据;

我们不可能把超级块和索引节点区全部加载到内存,这样内存肯定撑不住,所以只有当需要使用的时候,才将其加载进内存,它们加载进内存的时机是不同的.

●超级块:当文件系统挂载时进入内存;

●索引节点区:当文件被访问时进入内存;

文件系统的种类众多,而操作系统希望 对用户提供一个统一的接口 ,于是在用户层与文件系统层引入了中间层,这个中间层就称为 虚拟文件系统(Virtual File System, VFS) 。

VFS定义了一组所有文件系统都支持的数据结构和标准接口,这样程序员不需要了解文件系统的工作原理,只需要了解VFS提供的统一接口即可。

在Linux文件系统中,用户空间、系统调用、虚拟机文件系统、缓存、文件系统以及存储之间的关系如下图:

Linux支持的文件系统也不少,根据存储位置的不同,可以把文件系统分为三类:

●磁盘的文件系统,它是直接把数据存储在磁盘中,比如Ext 2/3/4. XFS 等都是这类文件系统。

●内存的文件系统,这类文件系统的数据不是存储在硬盘的,而是占用内存空间,我们经常用到的/proc 和/sys文件系统都属于这一类,读写这类文件,实际上是读写内核中相关的数据。

●网络的文件系统,用来访问其他计算机主机数据的文件系统,比如NFS. SMB等等。

文件系统首先要先挂载到某个目录才可以正常使用,比如Linux系统在启动时,会把文件系统挂载到根目录。

在操作系统的辅助之下,磁盘中的数据在计算机中都会呈现为易读的形式,并且我们不需要关心数据到底是如何存放在磁盘中,存放在磁盘的哪个地方等等问题,这些全部都是由操作系统完成的。

那么,文件数据在磁盘中究竟是怎么样的呢?我们来一探究竟!

磁盘中的存储单元会被划分为一个个的“ 块 ”,也被称为 扇区 ,扇区的大小一般都为512byte.这说明即使一块数据不足512byte,那么它也要占用512byte的磁盘空间。

而几乎所有的文件系统都会把文件分割成固定大小的块来存储,通常一个块的大小为4K。如果磁盘中的扇区为512byte,而文件系统的块大小为4K,那么文件系统的存储单元就为8个扇区。这也是前面提到的一个问题,文件大小和占用空间之间有什么区别?文件大小是文件实际的大小,而占用空间则是因为即使它的实际大小没有达到那么大,但是这部分空间实际也被占用,其他文件数据无法使用这部分的空间。所以我们 写入1byte的数据到文本中,但是它占用的空间也会是4K。

这里要注意在Windows下的NTFS文件系统中,如果一开始文件数据小于 1K,那么则不会分配磁盘块来存储,而是存在一个文件表中。但是一旦文件数据大于1K,那么不管以后文件的大小,都会分配以4K为单位的磁盘空间来存储。

与内存管理一样,为了方便对磁盘的管理,文件的逻辑地址也被分为一个个的文件块。于是文件的逻辑地址就是(逻辑块号,块内地址)。用户通过逻辑地址来操作文件,操作系统负责完成逻辑地址与物理地址的映射。

不同的文件系统为文件分配磁盘空间会有不同的方式,这些方式各自都有优缺点。

连续分配要求每个文件在磁盘上有一组连续的块,该分配方式较为简单。

通过上图可以看到,文件的逻辑块号的顺序是与物理块号相同的,这样就可以实现随机存取了,只要知道了第一个逻辑块的物理地址, 那么就可以快速访问到其他逻辑块的物理地址。那么操作系统如何完成逻辑块与物理块之间的映射呢?实际上,文件都是存放在目录下的,而目录是一种有结构文件, 所以在文件目录的记录中会存放目录下所有文件的信息,每一个文件或者目录都是一个记录。 而这些信息就包括文件的起始块号和占有块号的数量。

那么操作系统如何完成逻辑块与物理块之间的映射呢? (逻辑块号, 块内地址) -> (物理块号, 块内地址),只需要知道逻辑块号对应的物理块号即可,块内地址不变。

用户访问一个文件的内容,操作系统通过文件的标识符找到目录项FCB, 物理块号=起始块号+逻辑块号。 当然,还需要检查逻辑块号是否合法,是否超过长度等。因为可以根据逻辑块号直接算出物理块号,所以连续分配支持 顺序访问和随机访问 。

因为读/写文件是需要移动磁头的,如果访问两个相隔很远的磁盘块,移动磁头的时间就会变长。使用连续分配来作为文件的分配方式,会使文件的磁盘块相邻,所以文件的读/写速度最快。

连续空间存放的方式虽然读写效率高,但是有 磁盘空间碎片 和 文件长度不易扩展 的缺陷。

如下图,如果文件B被删除,磁盘上就留下一块空缺,这时,如果新来的文件小于其中的一个空缺,我们就可以将其放在相应空缺里。但如果该文件的大小大于所

有的空缺,但却小于空缺大小之和,则虽然磁盘上有足够的空缺,但该文件还是不能存放。当然了,我们可以通过将现有文件进行挪动来腾出空间以容纳新的文件,但是这个在磁盘挪动文件是非常耗时,所以这种方式不太现实。

另外一个缺陷是文件长度扩展不方便,例如上图中的文件A要想扩大一下,需要更多的磁盘空间,唯一的办法就只能是挪动的方式,前面也说了,这种方式效率是非常低的。

那么有没有更好的方式来解决上面的问题呢?答案当然有,既然连续空间存放的方式不太行,那么我们就改变存放的方式,使用非连续空间存放方式来解决这些缺陷。

非连续空间存放方式分为 链表方式 和 索引方式 。

链式分配采取离散分配的方式,可以为文件分配离散的磁盘块。它有两种分配方式:显示链接和隐式链接。

隐式链接是只目录项中只会记录文件所占磁盘块中的第一块的地址和最后一块磁盘块的地址, 然后通过在每一个磁盘块中存放一个指向下一 磁盘块的指针, 从而可以根据指针找到下一块磁盘块。如果需要分配新的磁盘块,则使用最后一块磁盘块中的指针指向新的磁盘块,然后修改新的磁盘块为最后的磁盘块。

我们来思考一个问题, 采用隐式链接如何将实现逻辑块号转换为物理块号呢?

用户给出需要访问的逻辑块号i,操作系统需要找到所需访问文件的目录项FCB.从目录项中可以知道文件的起始块号,然后将逻辑块号0的数据读入内存,由此知道1号逻辑块的物理块号,然后再读入1号逻辑块的数据进内存,此次类推,最终可以找到用户所需访问的逻辑块号i。访问逻辑块号i,总共需要i+ 1次磁盘1/0操作。

得出结论: 隐式链接分配只能顺序访问,不支持随机访问,查找效率低 。

我们来思考另外一个问题,采用隐式链接是否方便文件拓展?

我们知道目录项中存有结束块号的物理地址,所以我们如果要拓展文件,只需要将新分配的磁盘块挂载到结束块号的后面即可,修改结束块号的指针指向新分配的磁盘块,然后修改目录项。

得出结论: 隐式链接分配很方便文件拓展。所有空闲磁盘块都可以被利用到,无碎片问题,存储利用率高。

显示链接是把用于链接各个物理块的指针显式地存放在一张表中,该表称为文件分配表(FAT, File Allocation Table)。

由于查找记录的过程是在内存中进行的,因而不仅显着地 提高了检索速度 ,而且 大大减少了访问磁盘的次数 。但也正是整个表都存放在内存中的关系,它的主要的缺点是 不适 用于大磁盘 。

比如,对于200GB的磁盘和1KB大小的块,这张表需要有2亿项,每一项对应于这2亿个磁盘块中的一个块,每项如果需要4个字节,那这张表要占用800MB内存,很显然FAT方案对于大磁盘而言不太合适。

一直都在,加油!(*゜Д゜)σ凸←自爆按钮

链表的方式解决了连续分配的磁盘碎片和文件动态打展的问题,但是不能有效支持直接访问(FAT除外) ,索引的方式可以解决这个问题。

索引的实现是为每个文件创建一个 索引数据块 ,里面存放的 是指向文件数据块的指针列表 ,说白了就像书的目录一样,要找哪个章节的内容,看目录查就可以。

另外, 文件头需要包含指向索引数据块的指针 ,这样就可以通过文件头知道索引数据块的位置,再通过索弓|数据块里的索引信息找到对应的数据块。

创建文件时,索引块的所有指针都设为空。当首次写入第i块时,先从空闲空间中取得一个块, 再将其地址写到索引块的第i个条目。

索引的方式优点在于:

●文件的创建、增大、缩小很方便;

●不会有碎片的问题;

●支持顺序读写和随机读写;

由于索引数据也是存放在磁盘块的,如果文件很小,明明只需一块就可以存放的下,但还是需要额外分配一块来存放索引数据,所以缺陷之一就是存储索引带来的开销。

如果文件很大,大到一个索引数据块放不下索引信息,这时又要如何处理大文件的存放呢?我们可以通过组合的方式,来处理大文件的存储。

先来看看 链表+索引 的组合,这种组合称为 链式索引块 ,它的实现方式是在 索引数据块留出一个存放下一个索引数据块的指针 ,于是当一个索引数据块的索引信息用完了,就可以通过指针的方式,找到下一个索引数据块的信息。那这种方式也会出现前面提到的链表方式的问题,万一某个指针损坏了,后面的数据也就会无法读取了。

还有另外一种组合方式是 索引+索引 的方式,这种组合称为多级索引块,实现方式是通过一个索引块来存放多个索引数据块,一层套一层索引, 像极了俄罗斯套娃是吧๑乛◡乛๑ 

前面说到的文件的存储是针对已经被占用的数据块组织和管理,接下来的问题是,如果我要保存一个数据块, 我应该放在硬盘上的哪个位置呢?难道需要将所有的块扫描一遍,找个空的地方随便放吗?

那这种方式效率就太低了,所以针对磁盘的空闲空间也是要引入管理的机制,接下来介绍几种常见的方法:

●空闲表法

●空闲链表法

●位图法

空闲表法

空闲表法就是为所有空闲空间建立一张表,表内容包括空闲区的第一个块号和该空闲区的块个数,注意,这个方式是连续分配的。如下图:

当请求分配磁盘空间时,系统依次扫描空闲表里的内容,直到找到一个合适的空闲区域为止。当用户撤销一个文件时,系统回收文件空间。这时,也需顺序扫描空闲表,寻找一个空闲表条目并将释放空间的第一个物理块号及它占用的块数填到这个条目中。

这种方法仅当有少量的空闲区时才有较好的效果。因为,如果存储空间中有着大量的小的空闲区,则空闲表变得很大,这样查询效率会很低。另外,这种分配技术适用于建立连续文件。

空闲链表法

我们也可以使用链表的方式来管理空闲空间,每一个空闲块里有一个指针指向下一个空闲块,这样也能很方便的找到空闲块并管理起来。如下图:

当创建文件需要一块或几块时,就从链头上依次取下一块或几块。反之,当回收空间时,把这些空闲块依次接到链头上。

这种技术只要在主存中保存一个指针, 令它指向第一个空闲块。其特点是简单,但不能随机访问,工作效率低,因为每当在链上增加或移动空闲块时需要做很多1/0操作,同时数据块的指针消耗了一定的存储空间。

空闲表法和空闲链表法都不适合用于大型文件系统,因为这会使空闲表或空闲链表太大。

位图法

位图是利用二进制的一位来表示磁盘中一个盘块的使用情况,磁盘上所有的盘块都有一个二进制位与之对应。

当值为0时,表示对应的盘块空闲,值为1时,表示对应的盘块已分配。它形式如下:

在Linux文件系统就采用了位图的方式来管理空闲空间,不仅用于数据空闲块的管理,还用于inode空闲块的管理,因为inode也是存储在磁盘的,自然也要有对其管理。

前面提到Linux是用位图的方式管理空闲空间,用户在创建一个新文件时, Linux 内核会通过inode的位图找到空闲可用的inode,并进行分配。要存储数据时,会通过块的位图找到空闲的块,并分配,但仔细计算一下还是有问题的。

数据块的位图是放在磁盘块里的,假设是放在一个块里,一个块4K,每位表示一个数据块,共可以表示4 * 1024 * 8 = 2^15个空闲块,由于1个数据块是4K大小,那么最大可以表示的空间为2^15 * 4 * 1024 = 2^27个byte,也就是128M。

也就是说按照上面的结构,如果采用(一个块的位图+ 一系列的块),外加一(个块的inode的位图+一系列的inode)的结构能表示的最大空间也就128M,

这太少了,现在很多文件都比这个大。

在Linux文件系统,把这个结构称为一个 块组 ,那么有N多的块组,就能够表示N大的文件。

最终,整个文件系统格式就是下面这个样子。

最前面的第一个块是引导块,在系统启动时用于启用引导,接着后面就是一个一个连续的块组了,块组的内容如下:

● 超级块 ,包含的是文件系统的重要信息,比如inode总个数、块总个数、每个块组的inode个数、每个块组的块个数等等。

● 块组描述符 ,包含文件系统中各个块组的状态,比如块组中空闲块和inode的数目等,每个块组都包含了文件系统中“所有块组的组描述符信息”。

● 数据位图和inode位图 ,用于表示对应的数据块或inode是空闲的,还是被使用中。

● inode 列表 ,包含了块组中所有的inode, inode 用于保存文件系统中与各个文件和目录相关的所有元数据。

● 数据块 ,包含文件的有用数据。

你可以会发现每个块组里有很多重复的信息,比如 超级块和块组描述符表,这两个都是全局信息,而且非常的重要 ,这么做是有两个原因:

●如果系统崩溃破坏了超级块或块组描述符,有关文件系统结构和内容的所有信息都会丢失。如果有冗余的副本,该信息是可能恢复的。

●通过使文件和管理数据尽可能接近,减少了磁头寻道和旋转,这可以提高文件系统的性能。

不过,Ext2 的后续版本采用了稀疏技术。该做法是,超级块和块组描述符表不再存储到文件系统的每个块组中,而是只写入到块组0、块组1和其他ID可以表示为3、5、7的幂的块组中。

在前面,我们知道了一个普通文件是如何存储的,但还有一个特殊的文件,经常用到的目录,它是如何保存的呢?

基于Linux 一切切皆文件的设计思想,目录其实也是个文件,你甚至可以通过vim打开它,它也有inode, inode 里面也是指向一些块。

和普通文件不同的是, 普通文件的块里面保存的是文件数据,而目录文件的块里面保存的是目录里面一项一项的文件信息 。

在目录文件的块中,最简单的保存格式就是 列表 ,就是一项一项地将目录下的文件信息(如文件名、文件inode.文件类型等)列在表里。

列表中每一项就代表该目录下的文件的文件名和对应的inode,通过这个inode,就可以找到真正的文件。

通常,第一项是“则”,表示当前目录,第二项是.,表示上一级目录, 接下来就是一项一项的文件名和inode。

如果一个目录有超级多的文件,我们要想在这个目录下找文件,按照列表一项一项的找,效率就不高了。

于是,保存目录的格式改成 哈希表 ,对文件名进行哈希计算,把哈希值保存起来,如果我们要查找一个目录下面的文件名,可以通过名称取哈希。如果哈希能够匹配上,就说明这个文件的信息在相应的块里面。

Linux系统的ext文件系统就是采用了哈希表,来保存目录的内容,这种方法的优点是查找非常迅速,插入和删除也较简单,不过需要一些预备措施来避免哈希冲突。

目录查询是通过在磁盘上反复搜索完成,需要不断地进行/0操作,开销较大。所以,为了减少/0操作,把当前使用的文件目录缓存在内存,以后要使用该文件时只要在内存中操作,从而降低了磁盘操作次数,提高了文件系统的访问速度。

感谢您的阅读,希望您能摄取到知识!加油!冲冲冲!(发现光,追随光,成为光,散发光!)我是程序员耶耶!有缘再见。<-biubiu-⊂(`ω´∩)

9. 解决碎片问题,以及使程序可浮动的最好的办法是采用什么技术

内存碎片是一个很棘手的问题。如何分配内存决定着内存碎片是否会、何时会、如何会成为一个问题。 即使在系统中事实上仍然有许多空闲内存时,内存碎片还会最终导致出现内存用完的情况。一个不断产生内存碎片的系统,不管产生的内存碎片多么小,只要时间足够长,就会将内存用完。这种情况在许多嵌入式系统中,特别是在高可用性系统中是不可接受的。有些软件环境,如 OSE 实时操作系统已经备有避免内存碎片的良好工具,但个别程序员做出的选择仍然会对最终结果形成影响。
“碎片的内存”描述一个系统中所有不可用的空闲内存。这些资源之所以仍然未被使用,是因为负责分配内存的分配器使这些内存无法使用。这一问题通常都会发生,原因在于空闲内存以小而不连续方式出现在不同的位置。由于分配方法决定内存碎片是否是一个问题,因此内存分配器在保证空闲资源可用性方面扮演着重要的角色。 编译时间与运行时间

10. 碎片化问题是什么

其实磁盘碎片应该称为文件碎片,是因为文件被分散保存到整个磁盘的不同地方,而不是连续地保存在磁盘连续的簇中形成的。 当应用程序所需的物理内存不足时,一般操作系统会在硬盘中产生临时交换文件,用该文件所占用的硬盘空间虚拟成内存。

阅读全文

与程序员的文件碎片相关的资料

热点内容
软通动力程序员节2021 浏览:845
安卓系统如何卸载安装包 浏览:868
短信删除助手文件夹 浏览:688
java办公自动化 浏览:340
php中超链接 浏览:253
linux默认路由设置 浏览:36
linux如何挂载iso 浏览:432
vs程序换文件夹后不能编译 浏览:557
安卓源码编译输入脚本没反应 浏览:47
phpmysql自增 浏览:167
把ppt保存为pdf 浏览:533
汽车密封件加密配件 浏览:887
黑马程序员15天基础班 浏览:560
java调整格式 浏览:521
香港云服务器租用价 浏览:78
linuxsublime3 浏览:560
imac混合硬盘命令 浏览:278
沈阳用什么app租房车 浏览:857
00后高中生都用什么app 浏览:239
戴尔塔式服务器怎么打开独立显卡 浏览:808