精华内容
下载资源
问答
  • 你可以认为碎片是部分activity的模块化。它有自己的生命周期,接受自己输入事件,可以在activity运行时被添加和删除(类似个子activity,你可以在不同的activity中复用)。这个课程展示了怎么使用支持库扩展...
    你可以认为碎片是部分activity的模块化。它有自己的生命周期,接受自己输入事件,可以在activity运行时被添加和删除(类似一个子activity,你可以在不同的activity中复用)。这个课程展示了怎么使用支持库扩展Fragment类,让Android1.6这样的老版本也能兼容你的程序。
    

    提示:如果你的最小API级别是11或者更高,你就不需要使用支持库,可以直接使用框架构建Fragment类和相关API。这个课程关注的是使用支持库中的API,和那些直接包含在平台中的版本,这些API使用特别的包名和稍微不同的API名称。

    创建一个碎片类

    创建一个碎片需要扩展Fragment类,在程序中覆盖关键生命周期方法,类似于使用Activity类。

    一个不同点是,你需要在onCreateView()回调中定义布局,事实上,这是让碎片运行起来唯一一个使用的回调。例如,下面是一个简单碎片,指定了它自己的布局:
    import android.os.Bundle;
    import android.support.v4.app.Fragment;
    import android.view.LayoutInflater;
    import android.view.ViewGroup;
    
    public class ArticleFragment extends Fragment {
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container, 
            Bundle savedInstanceState) {
            // 给碎片填充布局
            return inflater.inflate(R.layout.article_view, container, false);
        }
    }
    和activity一样,一个fragment需要实现其他生命周期回调,允许你管理它从activity被添加或者删除时的状态,像activity转换她的生命周期状态一样。例如,当activity的onPause()函数被调用时,activity中所有的碎片也都会接收一个onPause()调用。

    更多关于碎片生命周期函数的信息,可以参考这里: Fragments

    使用XML添加一个碎片到activity中

    虽然碎片是可重用,模块化的UI组件,每个Fragment类的实例都必须关联一个父类FragmentActivity。你可以定义每个碎片在你的activity布局XML文件中来实现这个联系。

    提示:FragmentActivity是一个特别的activity,支持库提供它来管理API级别11以下的碎片。如果你支持的最低版本是11或者更高,你可以直接使用Activity。

    下面是一个布局文件的实例,在设备是large屏幕(在目录名中指定了large限定符)时,添加两个碎片到一个activity中。

    res/layout-large/news_articles.xml:
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="horizontal"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent">
    
        <fragment android:name="com.example.android.fragments.HeadlinesFragment"
                  android:id="@+id/headlines_fragment"
                  android:layout_weight="1"
                  android:layout_width="0dp"
                  android:layout_height="match_parent" />
    
        <fragment android:name="com.example.android.fragments.ArticleFragment"
                  android:id="@+id/article_fragment"
                  android:layout_weight="2"
                  android:layout_width="0dp"
                  android:layout_height="match_parent" />
    
    </LinearLayout>
    补充:更多关于不同尺寸布局文件的支持,请看 Supporting Different Screen Sizes.

    这里是一个activity怎么应用这个布局:
    import android.os.Bundle;
    import android.support.v4.app.FragmentActivity;
    
    public class MainActivity extends FragmentActivity {
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.news_articles);
        }
    }
    提示:当你在布局XML文件中为activity添加碎片时,你不可以在运行时移除碎片。如果你打算在用户交互时换入和换出碎片,你必须在activity第一启动时添加碎片,请看下一课。

    展开全文
  • 什么是磁盘碎片

    千次阅读 2018-10-11 13:49:54
    实际上,磁盘碎片应该称为文件碎片,因为文件会分别保存到整个磁盘的不同位置,而不是连续保存在磁盘的连续群集中。   当应用程序所需的物理内存不足时,通常操作系统会在硬盘上生成临时交换文件。此临时交换文件...

    实际上,磁盘碎片应该称为文件碎片,因为文件会分别保存到整个磁盘的不同位置,而不是连续保存在磁盘的连续群集中。

     

    当应用程序所需的物理内存不足时,通常操作系统会在硬盘上生成临时交换文件。此临时交换文件占用的磁盘空间用于形成虚拟内存。虚拟内存的管理程序将经常在硬盘上读写并产生大量碎片。这是硬盘碎片化的主要原因。除此之外,系统中的临时文件会导致很多碎片。当IE浏览器浏览信息或用户直接设置它们时生成临时文件。频繁的磁盘碎片整理可以提高计算机硬盘的服务效率。

    • 定义

     

    磁盘碎片是指在读写硬盘过程中产生的不连续文件。写在硬盘上的非连续文件可能会产生碎片,碎片会延长硬盘寻道时间并影响系统性能。例如,如果虚拟内存占用磁盘,则硬盘驱动器上将存在磁盘碎片。

     

    • 产生原因

     

    在文件操作过程中,Windows系统可能会调用虚拟内存来同步管理程序。这将使许多程序在硬盘上频繁读写。另一种情况是,在删除中间的集群(由扇区组成)的内容之后,将较小的新文件写入磁盘。这两个文件的两侧都会有一些空间。此时,写入另一个文件,但这两个空间的任何部分都无法保存此文件。该文件将分为两部分。碎片再次产生。

     

    下载像电影这样的大文件是最常见的。在下载过程中,人们通常会处理其他事情。下载的电影文件被强制分成几个片段并存储在硬盘上。因此,下载是碎片化的重要原因。更重要的是,频繁删除和添加文件也是碎片化的原因。如果保存这些文件的空间不够大,将生成大量磁盘碎片。随着频繁删除文件,这种情况将变得越来越严重。

     

    虽然磁盘碎片不会影响正常工作,但它会显着降低硬盘的运行速度。这主要是因为硬盘在读取文件时需要在多个部分之间跳转。等待盘旋转到指定扇区并寻找头切换轨道时间的延迟增加。

     

    计算机使用很长时间后,磁盘会保存很多文件。这些文件不会保存在连续的磁盘空间中,而是单独保存在某些位置。这些碎片文件称为“磁盘碎片”。这些部分将降低Windows的整体性能。每次读取和写入文件时,磁盘联系都需要来回移动。这是浪费时间。因此,Windows提供了一个碎片整理程序。

     

    • 运营原则

     

    在了解磁盘碎片的原因后,我们还需要在程序运行时知道磁盘读写操作。通常,当我们运行一个程序时,磁盘驱动程序的头部将执行以下工作:搜索运行此程序所需的文件,读取数据,执行读取处理以及将数据传输到磁盘缓存和内存。搜索时间称为硬盘性能指标的平均搜索时间。它以毫秒(ms)为单位指定。磁盘的平均查找时间小于9.5毫秒。如果应用程序的相关文档可以放在连续的磁盘空间中,则磁头的搜索时间会减少很多。阅读也一样。磁盘读取磁头下方扇区所需的时间仅为将磁头移动到另一个位置然后读取相同数据所需时间的1/5。读取磁盘时,系统将检查数据是否在缓存中。如果是,他们将被直接阅读;如果没有,将访问磁盘。这称为读取磁盘。当需要多次读取相同的数据时,缓存起着很大的作用。但是如果第一次读取文件,缓存就无法做任何事情。搜索时间和读取时间很大程度上影响程序执行的效率。

     

    我们为什么要对磁盘进行碎片整理?我们进行磁盘碎片整理,因为Windows系统不能按照减少磁头搜索时间的原则将每个文件放在磁盘的适当位置。因此,Microsoft将“磁盘碎片整理”添加到Windows,并提供“任务监视器”来跟踪程序启动期间的磁盘活动。跟踪磁盘活动使“磁盘碎片整理”有效工作。

     

    任务监视器仅在程序加载过程中搜索文件信息。它将根据程序的加载频率调整和优化顺序。这意味着最常使用的软件将得到最佳优化。但是,如果用户更改常用软件,例如将WinZip更改为ZipMagic,那么很长一段时间,磁盘碎片整理仍会将与WinZip相关的文件而不是ZipMagic移动到连续空间。除非ZipMagic的加载时间超过WinZip的加载时间。要解决此问题,用户可以删除“Winzip32.lgx”。如果日志文件不存在,则磁盘碎片整理不会对其进行优化。

     

    • 外部碎片和内部碎片

     

    很多人会对文件碎片和集群的概念感到困惑。实际上,对于Windows系统,硬盘上的每个分区都由最小的存储单元 - 集群组成。这就像是通过转动一个街区组成一面墙。格式化分区时,用户可以定义群集的大小。它通常是几KB的大小,例如8 KB。例如,我有一个文件,其大小为800 MB点1 KB(1 MB = 1000 KB)。 800 MB等于80,001 KB。其中80,000 KB占用10,000个集群。其余的1 KB也必须占用1个集群。但是,没有使用7 KB的空间。并且其他文件不能占用未充分使用的此群集。这会造成一点浪费的空间。许多人称浪费7 KB空间作为磁盘上的内部碎片。但是,用户可以更改群集大小以充分利用磁盘空间。

     

    外部碎片(通常称为磁盘碎片。磁盘碎片整理工具只能清除硬盘上的外部碎片。除非你更改硬盘上的分配单元,即文件系统的簇大小使其成为文件大小的整数倍)表示一个文件占用的非连续簇。这相当于文件被分割并分别保存在不连续的簇段上。根据文件分成的部分数量将有几个部分。因此,碎片实际上是指文件碎片。这可以理解为文件已被分解成碎片。有时,文件片段之间的序列是无序的。例如,有时在硬盘上由“后向文件片段”占用的簇段可能位于“前文件片段”簇段的前排。结果,文件将以混乱的顺序存储在硬盘上。

     

    • 破坏硬盘

     

    必要性

     

    实际上,毫无疑问我们需要定期对硬盘进行碎片整理。如果硬盘碎片整理真的会损坏硬盘驱动器,经过多次碎片整理后会损坏它。如果硬盘已经使用了很长时间,文件的存储位置将变得碎片化——文件内容将分散在硬盘上的不同位置。这些碎片文件的存在将降低磁盘的工作效率,并增加数据丢失和数据损坏的可能性。碎片整理程序收集这些碎片并将它们作为一个整体保存在磁盘上。

     

    整理周期

     

    个人用户每三个月一次。

     

    企业用户和政府用户每月一次。

     

    执行磁盘碎片整理时,必须关闭屏幕保护程序,不得在计算机上执行其他操作,例如听音乐和玩游戏。您应该让计算机仅运行磁盘碎片整理程序以防止丢失数据。同时,不建议频繁对硬盘进行碎片整理,因为在这种情况下,硬盘不会停止读写。这会影响硬盘的使用寿命。

    展开全文
  • 例如,手机中可能次只适合显示碎片,相反的,在大屏幕设备中,你可能想在个界面中挨着显示很多个碎片。 图解:个activity在不同屏幕尺寸的显示效果。在大屏幕中,两个碎片紧挨着显示,在手机中,...

    Android提供一个JAR文件的支持库,允许你在比较低的版本中使用一些新版本的API。例如,支持库提供了碎片API让你在Android1.6中可以使用。


    这个课程教你怎么设置支持库,使用碎片创建一个动态程序UI。

    使用支持库建立你的工程

    1. 使用SDK管理器下载支持库。

    2. 在工程更目录创建libs文件夹。
    3. 把JAR文件复制到libs目录中。
      比如,API级别4的支持库的位置是:<sdk>/extras/android/support/v4/android-support-v4.jar
    4. 修改你的清单文件,设置最低版本API级别为4,目标版本级别为最新:
      <uses-sdk android:minSdkVersion="4" android:targetSdkVersion="15" />

    引用支持库API

    支持库包含的各种API要么被已经被添加到最新的android版本中,要么更本不存在于平台中,而仅仅为低版本开发特别特征提供额外的支持。

    你可以在android.support.v4.*找到平台文档中支持库的API参考文档。

    警告:确保你不是在老版本中偶尔使用新的API,确定你从android.support.v4.app包中引用Fragment类和相关API。
    import android.support.v4.app.Fragment;
    import android.support.v4.app.FragmentManager;
    ...
    当使用支持库创建一个主碎片activity,你必须继承FragmentActivity类,而不是继承传统的Activity类。下一个课程有更多介绍。
    你可以认为碎片是部分activity的模块化。它有自己的生命周期,接受自己输入事件,可以在activity运行时被添加和删除(类似一个子activity,你可以在不同的activity中复用)。这个课程展示了怎么使用支持库扩展Fragment类,让Android1.6这样的老版本也能兼容你的程序。

    提示:如果你的最小API级别是11或者更高,你就不需要使用支持库,可以直接使用框架构建Fragment类和相关API。这个课程关注的是使用支持库中的API,和那些直接包含在平台中的版本,这些API使用特别的包名和稍微不同的API名称。

    创建一个碎片类

    创建一个碎片需要扩展Fragment类,在程序中覆盖关键生命周期方法,类似于使用Activity类。

    一个不同点是,你需要在onCreateView()回调中定义布局,事实上,这是让碎片运行起来唯一一个使用的回调。例如,下面是一个简单碎片,指定了它自己的布局:
    import android.os.Bundle;
    import android.support.v4.app.Fragment;
    import android.view.LayoutInflater;
    import android.view.ViewGroup;
    
    public class ArticleFragment extends Fragment {
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container, 
            Bundle savedInstanceState) {
            // 给碎片填充布局
            return inflater.inflate(R.layout.article_view, container, false);
        }
    }
    和activity一样,一个fragment需要实现其他生命周期回调,允许你管理它从activity被添加或者删除时的状态,像activity转换她的生命周期状态一样。例如,当activity的onPause()函数被调用时,activity中所有的碎片也都会接收一个onPause()调用。

    更多关于碎片生命周期函数的信息,可以参考这里: Fragments

    使用XML添加一个碎片到activity中

    虽然碎片是可重用,模块化的UI组件,每个Fragment类的实例都必须关联一个父类FragmentActivity。你可以定义每个碎片在你的activity布局XML文件中来实现这个联系。

    提示:FragmentActivity是一个特别的activity,支持库提供它来管理API级别11以下的碎片。如果你支持的最低版本是11或者更高,你可以直接使用Activity。

    下面是一个布局文件的实例,在设备是large屏幕(在目录名中指定了large限定符)时,添加两个碎片到一个activity中。

    res/layout-large/news_articles.xml:
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="horizontal"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent">
    
        <fragment android:name="com.example.android.fragments.HeadlinesFragment"
                  android:id="@+id/headlines_fragment"
                  android:layout_weight="1"
                  android:layout_width="0dp"
                  android:layout_height="match_parent" />
    
        <fragment android:name="com.example.android.fragments.ArticleFragment"
                  android:id="@+id/article_fragment"
                  android:layout_weight="2"
                  android:layout_width="0dp"
                  android:layout_height="match_parent" />
    
    </LinearLayout>
    补充:更多关于不同尺寸布局文件的支持,请看 Supporting Different Screen Sizes.

    这里是一个activity怎么应用这个布局:
    import android.os.Bundle;
    import android.support.v4.app.FragmentActivity;
    
    public class MainActivity extends FragmentActivity {
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.news_articles);
        }
    }
    提示:当你在布局XML文件中为activity添加碎片时,你不可以在运行时移除碎片。如果你打算在用户交互时换入和换出碎片,你必须在activity第一启动时添加碎片,请看下一课。


    当设计你的程序去支持大部分屏幕尺寸时,你可以在不同的布局文件中复用你的碎片,在不同的屏幕空间中优化你的用户体验。


    例如,手机中可能一次只适合显示一个碎片,相反的,在大屏幕设备中,你可能想在一个界面中挨着显示很多个碎片。

    图解:一个activity在不同屏幕尺寸的显示效果。在大屏幕中,两个碎片紧挨着显示,在手机中,一次只显示一个碎片。

    FragmentManager类提供一些函数,让你可以在程序运行时添加,删除和替换碎片,从而产生动态显示效果。

    运行中添加一个碎片

    上一个教程中,我们在XML文件中添加碎片,不同的是,你现在可以在activity运行期间添加一个碎片,在activity生命周期中改变碎片是非常有必要的。

    要实现碎片的添加和删除,你需要使用FragmentManager去创建一个FragmentTransaction,它提供API去添加,删除,替换和执行其他碎片转换。

    如果你想允许碎片被移除和替换,你需要在activity的onCreate()函数中初始化碎片。

    一个重要的规定是:要操作碎片,尤其是运行中添加碎片,碎片必须有一个view容器,这个容器包含了碎片的布局。

    下面这个布局和上一个课程的有所不同,它一次只显示一个碎片。为了能用其他碎片替换这一个碎片,activity布局需要包含一个空的FrameLayout碎片容器。

    需要提醒的是,下面的文件名和上一课的一样,但是目录没有large限定符,所以,这个布局是当设备屏幕尺寸小于large的时候才会被应用,因为屏幕太小,不够同时显示多个碎片。

    res/layout/news_articles.xml:
    <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/fragment_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
    在你的activity中,调用getSupportFragmentManager()去取得一个FragmentManager。然后调用beginTransaction()去创建一个FragmentTransaction,再调用add()去添加一个碎片。

    你可以使用FragmentTransaction去处理多个碎片,当你确认好要改变碎片时,你必须调用commit()。

    例如,下面演示了怎么添加一个碎片:
    import android.os.Bundle;
    import android.support.v4.app.FragmentActivity;
    
    public class MainActivity extends FragmentActivity {
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.news_articles);
    
            // 检查activity使用的布局中是否有碎片容器
            if (findViewById(R.id.fragment_container) != null) {
    
                // 如果我们只是恢复先前的状态,
                // 那么我们什么都不用做,只是返回或者我们可以覆盖先前的碎片
                if (savedInstanceState != null) {
                    return;
                }
    
                // 创建一个碎片实例
                HeadlinesFragment firstFragment = new HeadlinesFragment();
                
                // 使用特别的指令从一个Intent开始一个activity,
                // 把Intent中附加的数据做为碎片的参数。
                firstFragment.setArguments(getIntent().getExtras());
                
                // 添加碎片到碎片容器中。
                getSupportFragmentManager().beginTransaction()
                        .add(R.id.fragment_container, firstFragment).commit();
            }
        }
    }
    因为随便是在运行中被添加到FrameLayout容器中的,所以activity可以用一个不同的碎片替换它,或者是删除它。

    用另外一个碎片替换当前碎片

    替换一个碎片的步骤和添加一样简单,只需要把add改为replace就可以了。

    记住,当你进行碎片操作时,比如替换或者删除,你需要让用户可以返回和撤销改变。为了实现这些,你需要在提交碎片操作前调用addToBackStack()。

    提示:当你删除或者替换一个碎片,并且添加了这些操作在后退堆栈,碎片移除会被停止(没有被销毁),如果用户想返回恢复碎片,它就会被重新开启。如果没有加入后退堆栈,这个碎片就会在替换或者删除的时候被销毁。

    替换的例子:
    // 创建一个碎片,传递一个参数给它,指定显示的内容。
    ArticleFragment newFragment = new ArticleFragment();
    Bundle args = new Bundle();
    args.putInt(ArticleFragment.ARG_POSITION, position);
    newFragment.setArguments(args);
    
    FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
    
    // 替换碎片容器中的碎片,
    // 添加操作到后退堆栈中,以便用户可以返回。
    transaction.replace(R.id.fragment_container, newFragment);
    transaction.addToBackStack(null);
    
    // 提交操作
    transaction.commit();
    addToBackStack()函数需要传递一个字符串参数,为操作指定一个独一无二的名称,这个名称不是必须的,除非你计划开始使用FragmentManager.BackStackEntryAPI执行高级的碎片操作。


    了能重复使用碎片UI组件,你需要创建一个完全独立,模块化的组件,这个组件可以定义自己的样式和行为。一旦你定义了一个可重用的碎片,你可以使用一个activity关联它们,通过程序逻辑链接它们成为一个完整的组合UI。

    通常你希望碎片间可以通信,比如基于用户事件改变内容。所有碎片间的通信都是通过activity实现,两个碎片不能直接通信。

    定义一个接口

    为了实现碎片和activity的通信,你可以在碎片类中定义一个接口,然后在activity中实现这个接口。碎片可以在onAttach()生命周期函数中取得接口的实现,然后调用接口方法实现通信。

    这里是一个碎片和activity通信的例子:
    public class HeadlinesFragment extends ListFragment {
        OnHeadlineSelectedListener mCallback;
    
        // Activity容器必须实现这个接口
        public interface OnHeadlineSelectedListener {
            public void onArticleSelected(int position);
        }
    
        @Override
        public void onAttach(Activity activity) {
            super.onAttach(activity);
            
            // 确保activity实现了接口回调,不然抛出一个异常
            try {
                mCallback = (OnHeadlineSelectedListener) activity;
            } catch (ClassCastException e) {
                throw new ClassCastException(activity.toString()
                        + " must implement OnHeadlineSelectedListener");
            }
        }
        
        ...
    }
    现在碎片可以使用OnHeadloneSelectedListener接口的mCallback实例调用onArticleSelected()函数(或者接口中其他函数)发送信息给activity了。

    例如,当用户点击list选项时,碎片中的下面这个方法会被调用。碎片使用回调接口发送事件给父类activity。
        @Override
        public void onListItemClick(ListView l, View v, int position, long id) {
            // Send the event to the host activity
            mCallback.onArticleSelected(position);
        }

    实现接口

    为了从碎片中接收事件回调,拥有这个碎片的activity必须实现定义在碎片类中的接口。

    例如,下面的代码实现了上面例子中定义的接口:
    public static class MainActivity extends Activity
            implements HeadlinesFragment.OnHeadlineSelectedListener{
        ...
        
        public void onArticleSelected(Uri articleUri) {
            // The user selected the headline of an article from the HeadlinesFragment
            // Do something here to display that article
        }
    }

    发送一个信息给碎片

    通过findFragmentById()取得Fragment实例,然后activity就可以直接调用碎片的公共函数发送信息给这个fragment。

    例如,上面的函数让activity显示了一个碎片选项的数据,activity也可以通过信息接收函数去显示其他碎片数据:
    public static class MainActivity extends Activity
            implements HeadlinesFragment.OnHeadlineSelectedListener{
        ...
    
        public void onArticleSelected(int position) {
            // 用户从文章标题碎片选择标题
            // 这里可以写一些显示文章的代码
    
            ArticleFragment articleFrag = (ArticleFragment)
                    getSupportFragmentManager().findFragmentById(R.id.article_fragment);
    
            if (articleFrag != null) {
                // 如果是文章显示页面碎片
    
                // 呼叫一个更新内容的方法
                articleFrag.updateArticleView(position);
            } else {
                // 否则我们在第一个布局页面
    
                // 创建一个碎片,给选择项传递一个参数
                ArticleFragment newFragment = new ArticleFragment();
                Bundle args = new Bundle();
                args.putInt(ArticleFragment.ARG_POSITION, position);
                newFragment.setArguments(args);
            
                FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
    
                // 替换碎片的内容,
                // 添加改变到回退堆栈,以便用户返回
                transaction.replace(R.id.fragment_container, newFragment);
                transaction.addToBackStack(null);
    
                // 提交更改
                transaction.commit();
            }
        }
    }


    展开全文
  • 内部碎片 外部碎片

    千次阅读 2013-10-29 23:07:44
    内存碎片的产生:  内存分配有静态分配和动态分配两种  静态分配在程序编译链接时分配的大小和使用寿命就已经确定,而应用上...内存碎片即“碎片的内存”描述个系统中所有不可用的空闲内存,这些碎片之所以不能

    内存碎片的产生:

            内存分配有静态分配和动态分配两种
           静态分配在程序编译链接时分配的大小和使用寿命就已经确定,而应用上要求操作系统可以提供给进程运行时申请和释放任意大小内存的功能,这就是内存的动态分配。
            因此动态分配将不可避免会产生内存碎片的问题,那么什么是内存碎片?内存碎片即“碎片的内存”描述一个系统中所有不可用的空闲内存,这些碎片之所以不能被使用,是因为负责动态分配内存的分配算法使得这些空闲的内存无法使用,这一问题的发生,原因在于这些空闲内存以小且不连续方式出现在不同的位置。因此这个问题的或大或小取决于内存管理算法的实现上。

           为什么会产生这些小且不连续的空闲内存碎片呢?

           实际上这些空闲内存碎片存在的方式有两种:a.内部碎片 b.外部碎片 。
           内部碎片的产生:因为所有的内存分配必须起始于可被 4、8 或 16 整除(视处理器体系结构而定)的地址或者因为MMU的分页机制的限制,决定内存分配算法仅能把预定大小的内存块分配给客户。假设当某个客户请求一个 43 字节的内存块时,因为没有适合大小的内存,所以它可能会获得 44字节、48字节等稍大一点的字节,因此由所需大小四舍五入而产生的多余空间就叫内部碎片。
          外部碎片的产生: 频繁的分配与回收物理页面会导致大量的、连续且小的页面块夹杂在已分配的页面中间,就会产生外部碎片。假设有一块一共有100个单位的连续空闲内存空间,范围是0~99。如果你从中申请一块内存,如10个单位,那么申请出来的内存块就为0~9区间。这时候你继续申请一块内存,比如说5个单位大,第二块得到的内存块就应该为10~14区间。如果你把第一块内存块释放,然后再申请一块大于10个单位的内存块,比如说20个单位。因为刚被释放的内存块不能满足新的请求,所以只能从15开始分配出20个单位的内存块。现在整个内存空间的状态是0~9空闲,10~14被占用,15~24被占用,25~99空闲。其中0~9就是一个内存碎片了。如果10~14一直被占用,而以后申请的空间都大于10个单位,那么0~9就永远用不上了,变成外部碎片。


     

    如何解决内存碎片:

            采用Slab Allocation机制:整理内存以便重复使用
            最近的memcached默认情况下采用了名为Slab Allocator的机制分配、管理内存。在该机制出现以前,内存的分配是通过对所有记录简单地进行malloc和free来进行的。但是,这种方式会导致内存碎片,加重操作系统内存管理器的负担,最坏的情况下,会导致操作系统比memcached进程本身还慢。Slab Allocator就是为解决该问题而诞生的。
            下面来看看Slab Allocator的原理。下面是memcached文档中的slab allocator的目标:he primary goal of the slabs subsystem in memcached was to eliminate memory fragmentation issuestotally by using fixedsizememory chunks coming from a few predetermined size classes.
            也就是说,Slab Allocator的基本原理是按照预先规定的大小,将分配的内存分割成特定长度的块,以完全解决内存碎片问题。Slab Allocation的原理相当简单。将分配的内存分割成各种尺寸的块(chunk),并把尺寸相同的块分成组(chunk的集合)(图2.1)。

      slab allocator还有重复使用已分配的内存的目的。也就是说,分配到的内存不会释放,而是重复利用

    Slab Allocation的主要术语
        Page
        分配给Slab的内存空间,默认是1MB。分配给Slab之后根据slab的大小切分成chunk。
        Chunk
        用于缓存记录的内存空间。
        Slab Class
        特定大小的chunk的组。

    在Slab中缓存记录的原理
    下面说明memcached如何针对客户端发送的数据选择slab并缓存到chunk中。memcached根据收到的数据的大小,选择最适合数据大小的slab(图2.2)。memcached中保存着slab内空闲chunk的列表,根据该列表选择chunk,然后将数据缓存于其中。

     
    图2.2:选择存储记录的组的方法
    实际上,Slab Allocator也是有利也有弊。下面介绍一下它的缺点。

    Slab Allocator的缺点
    Slab Allocator解决了当初的内存碎片问题,但新的机制也给memcached带来了新的问题。这个问题就是,由于分配的是特定长度的内存,因此无法有效利用分配的内存。例如,将100字节的数据缓存到128字节的chunk中,剩余的28字节就浪费了

     对于该问题目前还没有完美的解决方案,但在文档中记载了比较有效的解决方案。
    The most efficient way to reduce the waste is to use a list of size classes that closely matches (if that's at all
    possible) common sizes of objects that the clients of this particular installation of memcached are likely to
    store.
           就是说,如果预先知道客户端发送的数据的公用大小,或者仅缓存大小相同的数据的情况下,只要使用适合数据大小的组的列表,就可以减少浪费。但是很遗憾,现在还不能进行任何调优,只能期待以后的版本了。但是,我们可以调节slab class的大小的差别

     

    最佳适合与最差适合分配程序
      最佳适合算法在功能上与最先适合算法类似,不同之处是,系统在分配一个内存块时,要搜索整个自由表,寻找最接近请求存储量的内存块。这种搜索所花的时间要比最先适合算法长得多,但不存在分配大小内存块所需时间的差异。最佳适合算法产生的内存碎片要比最先适合算法多,因为将小而不能使用的碎片放在自由表开头部分的排序趋势更为强烈。由于这一消极因素,最佳适合算法几乎从来没有人采用过。
      最差适合算法也很少采用。最差适合算法的功能与最佳适合算法相同,不同之处是,当分配一个内存块时,系统在整个自由表中搜索与请求存储量不匹配的内存快。这种方法比最佳适合算法速度快,因为它产生微小而又不能使用的内存碎片的倾向较弱。始终选择最大空闲内存块,再将其分为小内存块,这样就能提高剩余部分大得足以供系统使用的概率。
      伙伴(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 字节。

    展开全文
  • 什么碎片

    千次阅读 2014-08-07 13:32:15
    据我个人的意会 简单的说就是零碎的自由调用 因为现在大站页面已经不能用传统的程序自动编排来满足个性化的需求了 比如 我们要将 特定的文章显示在特定的位置 以前可能用自由调用...而碎片功能 强大在他的关联推送
  • Android碎片化Fragment实例

    千次阅读 2017-12-26 22:06:51
    我们再android中所说的碎片化也就是针对不同设备的屏幕大小设计不同的适配方案所说的词语。一般而言我们就是在开发时针对不同屏幕分辨率的设备适配UI,比如手机和平板。在本小节,我们主要是介绍Fragment的最简单...
  • 为了能重复使用碎片UI组件,你需要创建个完全独立,模块化的组件,这个组件可以定义自己的样式和行为。一旦你定义了个可重用的碎片,你可以使用个activity关联它们,通过程序逻辑链接它们成为个完整的组合UI...
  • 现在你已经将关于碎片的重要知识...那是不是就表明,我们开发的程序都需要提供个手机版和个 Pad 版呢?确实有不少公司都是这么做的,但是这样会浪费很多的人力物力。因为维护两个版本的代码成本很高,每当增加什么
  • 例如,手机中可能次只适合显示碎片,相反的,在大屏幕设备中,你可能想在个界面中挨着显示很多个碎片。 图解:个activity在不同屏幕尺寸的显示效果。在大屏幕中,两个碎片紧挨着显示,在手机中,...
  • 碎片和活动之间的通信用段很简单粗暴的逻辑来证明可行(本来就可行) 具体实现是在碎片中的EditText内写入文本 通过按钮点击 将文本内容显示在活动中的TextView中 这段是碎片的代码 里面定义了个EditText专门...
  • 在开发中,我们经常要用到碎片碎片与活动特别像,但却不是。在我们平常看到的平板与手机之间的app会清晰地...、我们可以创建碎片布局。命名为fragment_easy。&lt;LinearLayout xmlns:android="ht...
  • 单纯的分享,什么是Java堆碎片?这篇文章没有深入的讲解垃圾回收算法和垃圾回收器 有兴趣了解垃圾回收篇的知识的话,可以看我另篇三万字的文章哦! 1、Java堆碎片个有趣的问题,它会导致长时间暂停完整的垃圾...
  • 个简单的碎片的创建过程: 新建碎片布局,比如,fragment.xml 自定义个继承自Fragment类的类,并重写onCreateView()方法,动态加载碎片布局。 在被嵌入碎片的Activity的布局文件中加入标签,要注意添加an
  • 我们发现Redis服务器内存不够用了,但是我们的内存使用没有那么多呀,这是,就要看是否你的内存碎片率太大了。 碎片率的计算 我们登陆到Redis服务器上,执行以下命令: info memory 我们会看到如下的信息: 其中...
  • 内存碎片---内部碎片&外部碎片

    千次阅读 2018-05-05 20:44:01
    假设当某个客户请求个43字节的内存块时,因为没有适合大小的内存,所以它可能会获得 44字节、48字节等稍大一点的字节,因此由所需大小四舍五入而产生的多余空间就叫内部碎片。外部碎片的产生:频繁的分配与回收...
  • 磁盘碎片

    千次阅读 2009-01-11 13:34:00
    磁盘碎片,更确切地应该称为文件系统碎片。按照引文(1)的linux官方资料,可分为外部碎片(external fragmentation)和内部...假设簇大小为4KB,个大小不足1KB的文件也至少要分配个簇,即4KB的空间,这就浪费了大约3
  • 内存碎片

    2019-08-16 14:58:10
    内存碎片是指当系统报告内存耗尽时,而其实内存中也还存在未被使用的内存资源。 内存分配程序操作内存浪费的情况有:额外开销、外部碎片、内存碎片。 内存分配程序为管理内存,需存储一些描述其分配状态的信息,这些...
  • 内部碎片和外部碎片

    2019-05-20 22:00:10
    假设当某个客户请求个43字节的内存块时,因为没有适合大小的内存,所以它可能会获得 44字节、48字节等稍大一点的字节,因此由所需大小四舍五入而产生的多余空间就叫内部碎片。 外部碎片的产生:频繁的分配与回收...
  • oracle碎片

    千次阅读 2011-06-28 10:34:00
    author:skatetime:2010-05-31我们在使用windows的时候,都知道要定期整理磁盘碎片,因为磁盘碎片会影响性能,给管理上带来额外的负担。那oracle更是如此,当随着数据增加,oracle处理海量数据本身就已经很费力了啊...
  • 什么Linux不需要碎片整理?

    千次阅读 2014-01-16 12:44:56
    如果你是个Linux用户,你可能会听说Linux的文件系统不需要碎片整理。你也可能会注意到Linux的发行版本也都没有磁盘碎片整理的功能。这是为什么呢? 要理解为什么Linux的文件系统不会想Windows的文件系统一样产生...
  • 1. 碎片与 当碎片希望启动另碎片时, Fragment类 setTargetFragment(Fragment f, int requestCode)方法 支持调用碎片使用被调用碎片来设置它的身份. 看段示例代码: Fragment calledFragment = new Called...
  • 什么Linux不需要磁盘碎片整理

    千次阅读 2013-10-15 20:33:26
    为了理解为什么Linux文件系统不需要磁盘碎片整——而Windows却需要——你需要理解磁盘碎片产生的原理,以及Linux和Windows文件系统它们之间工作原理的不同之处。 什么是磁盘碎片 很多Windows用户
  • 碎片与外碎片

    千次阅读 2016-07-11 10:11:23
    在内存管理中,内部碎片是已经被分配出去的的内存空间大于请求所需的内存空间。... 为了有效的利用内存,使内存产生更少的碎片,要对内存分页,内存以页为单位来使用,最后页往往装不满,于是形成了内部
  • Oracle 碎片 优化

    千次阅读 2012-02-09 19:21:07
    说明:这个例子转自老白的DBA日记  刚刚坐下,电话就响了,个客户打过来的,说是碰到个很奇怪的问题。在一张上千万记录的大表里,做个SELECT * FROM WHERE ROWNUM --相关知识点参考:OracleSQLTrace 和 ...
  • 4.1 碎片什么 4.2 碎片的使用方式 4.2.1 碎片的简单用法 4.2.2 动态添加碎片 4.2.3 在碎片中模拟返回栈 4.2.4 碎片和活动之间进行通信 4.3 碎片的生命周期 4.3.1 碎片的状态和回调 4.3.2 体验碎片的生命...
  • 碎片采用顶部两个按钮,下面个FrameLayout,想在FrameLayout中显示副碎片,通过点击顶部两个按钮,在FrameLayout中加载不同的碎片,该如何实现?希望有会的朋友能指导一下,QQ563901809,十分感谢!![图片说明]...
  • 碎片Fragment

    千次阅读 2015-09-07 20:55:55
    Fragment简介Fragment即碎片,是种可以嵌入活动当中的UI片段,它能让程序更加合理和充分地利用大屏幕的空间,因而在平板上应用的非常广泛。它和活动很像,同样能包含布局,同样拥有自己的生命周期。碎片的出现就是...
  • Android之碎片的简单用法(静态添加) 注:静态添加fragment类似于添加自定义控件。 新建个 FragmentTest项目,然后开始我们的碎片探索之旅吧。 这里我们准备先写个最简单的碎片示例来练练手,在个活动当中...
  • 内存碎片和磁盘碎片

    2010-08-22 14:33:00
    内存碎片 内存碎片包括:内部碎片和外部碎片。 <br /> <br />内部碎片就是已经被分配出去(能明确指出属于哪个进程)却不能被利用的内存空间; 外部碎片指的是还没有被分配出去(不属于任何...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 250,380
精华内容 100,152
关键字:

一什么碎片