精华内容
下载资源
问答
  • java 分页

    2014-10-23 18:08:16
    第1种实现方式将数据库中的所有符合要求的数据一次性装入内存,然后通过List的sublist方法进行分页,优点在于不必频繁访问数据库,缺点是当数据量非常大的时候,对内存配置的要求比较高. 第2种实现方
    分页是我们在做项目的时候经常会遇到的技术点之一,分页技术从设计的角度考虑主要分为两大类:
    1.基于缓存的分页实现
    2.基于数据库查询的分页实现
    两者在使用上各有优缺点:
    第1种实现方式将数据库中的所有符合要求的数据一次性装入内存,然后通过List的sublist方法进行分页,优点在于不必频繁访问数据库,缺点是当数据量非常大的时候,对内存配置的要求比较高.
    第2种实现方式是通过数据库的限制条件,每次查询一定数目的数据,如通过oracle中的rownum加上where限制条件.优点在于每次取出一定数目的数据,内存使用较小,缺点是需要频繁的访问数据库.

    示例:

    1、定义分页模型:PageModel

    ?
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    package com.common.page; 
       
    import java.util.List; 
       
    /**
     * 封装分页信息
     * @author Administrator
     *
     */ 
    public class PageModel<E> { 
       
        //结果集 
        private List<E> list; 
           
        //查询记录数 
        private int totalRecords; 
           
        //每页多少条数据 
        private int pageSize; 
           
        //第几页 
        private int pageNo; 
           
        /**
         * 总页数
         * @return
         */ 
        public int getTotalPages() { 
            return (totalRecords + pageSize - 1) / pageSize; 
        
           
        /**
         * 取得首页
         * @return
         */ 
        public int getTopPageNo() { 
            return 1
        
           
        /**
         * 上一页
         * @return
         */ 
        public int getPreviousPageNo() { 
            if (pageNo <= 1) { 
                return 1
            
            return pageNo - 1
        
           
        /**
         * 下一页
         * @return
         */ 
        public int getNextPageNo() { 
            if (pageNo >= getBottomPageNo()) { 
                return getBottomPageNo(); 
            
            return pageNo + 1;   
        
           
        /**
         * 取得尾页
         * @return
         */ 
        public int getBottomPageNo() { 
            return getTotalPages(); 
        
           
        public List<E> getList() { 
            return list; 
        
       
        public void setList(List<E> list) { 
            this.list = list; 
        
       
        public int getTotalRecords() { 
            return totalRecords; 
        
       
        public void setTotalRecords(int totalRecords) { 
            this.totalRecords = totalRecords; 
        
       
        public int getPageSize() { 
            return pageSize; 
        
       
        public void setPageSize(int pageSize) { 
            this.pageSize = pageSize; 
        
       
        public int getPageNo() { 
            return pageNo; 
        
       
        public void setPageNo(int pageNo) { 
            this.pageNo = pageNo; 
        
    }
    2、分页测试:在MySQL中建立admin表,里面有字段id、name、password

    3、建立Admin的实体bean类:

    ?
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    package com.common.page; 
       
    public class Admin { 
        private int id; 
        private String name; 
        private String password; 
        public int getId() { 
            return id; 
        
        public void setId(int id) { 
            this.id = id; 
        
        public String getName() { 
            return name; 
        
        public void setName(String name) { 
            this.name = name; 
        
        public String getPassword() { 
            return password; 
        
        public void setPassword(String password) { 
            this.password = password; 
        
       
    }

    4、测试调用:
    ?
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    package com.common.page; 
       
    import java.sql.Connection; 
    import java.sql.PreparedStatement; 
    import java.sql.ResultSet; 
    import java.sql.SQLException; 
    import java.util.ArrayList; 
    import java.util.List; 
       
    import com.common.db.DbUtil; 
       
    public class Client { 
        public static PageModel findAdmins(int pageNo,int pageSize){ 
            Connection conn=DbUtil.getConnection(); 
            String sql="select * from admin limit ?,?"
            PageModel pageModel=null
            PreparedStatement pstm=null
            ResultSet rs=null
            Admin admin=null
            List<Admin> list=new ArrayList<Admin>(); 
            try
                pstm=conn.prepareStatement(sql); 
                pstm.setInt(1, (pageNo-1)*pageSize); 
                pstm.setInt(2, pageNo*pageSize); 
                rs=pstm.executeQuery();; 
                while(rs.next()){ 
                    admin=new Admin(); 
                    admin.setId(rs.getInt("a_id")); 
                    admin.setName(rs.getString("a_name")); 
                    admin.setPassword(rs.getString("a_pwd")); 
                    list.add(admin); 
                
                ResultSet rs2=pstm.executeQuery("select count(*) from admin"); 
                int total=0
                if(rs2.next()){ 
                    total=rs2.getInt(1); 
                
                pageModel=new PageModel(); 
                pageModel.setPageNo(pageNo); 
                pageModel.setPageSize(pageSize); 
                pageModel.setTotalRecords(total); 
                pageModel.setList(list); 
            catch (SQLException e) { 
                e.printStackTrace(); 
            }finally
                DbUtil.close(conn); 
                DbUtil.close(pstm); 
                DbUtil.close(rs); 
            
            return pageModel; 
        
           
        public static void main(String[] args) { 
            PageModel pageModel=Client.findAdmins(2,4); 
            List<Admin> list=pageModel.getList(); 
            for(Admin a:list){ 
                System.out.print("ID:"+a.getId()+",用户名:"+a.getName()+",密码:"+a.getPassword()); 
                System.out.println(); 
            
            System.out.print("当前页:"+pageModel.getPageNo()+" "); 
            System.out.print("共"+pageModel.getTotalPages()+"页  "); 
            System.out.print("首页:"+pageModel.getTopPageNo()+" "); 
            System.out.print("上一页:"+pageModel.getPreviousPageNo()+" "); 
            System.out.print("下一页:"+pageModel.getNextPageNo()+" "); 
            System.out.print("尾页:"+pageModel.getBottomPageNo()+" "); 
            System.out.print("共"+pageModel.getTotalRecords()+"条记录"); 
            System.out.println(); 
        
       
    }
    这样分页效果就实现了,我们要实现分页效果,只要传入相应的参数和相应的数据库执行语句即可实现,希望大家能灵活运用。
    展开全文
  • MyBatis插件分页

    2017-01-14 23:11:54
    说说各自的优缺点: 1.太麻烦了,每个要实现分页的都要写,扩展性不强 (放弃) 2.当数据库数据多的时候,效率极低,可能会出现内存溢出 3.需要自己实现interceptor接口,但是扩展性强 这里说一说分页的思路,以m
    MyBatis分页有3种方法:
    1.直接在映射文件里写sql语句,然后传参数
    2.在接口方法里加入参数 RowBounds
    3.利用插件实现分页


    说说各自的优缺点:
    1.太麻烦了,每个要实现分页的都要写,扩展性不强  (放弃)
    2.当数据库数据多的时候,效率极低,可能会出现内存溢出
    3.需要自己实现interceptor接口,但是扩展性强


    这里说一说分页的思路,以mysql为例子,就是用limit来实现分页
    我们为了实现分页,有一种思路就是拦截StatementHandler,在其编译sql语句前把sql改成我们要的样子,然后注入参数,最后查询得到分页效果,下面上代码


    package Model;
    
    public class Page {
    	private Integer currentPage;//当前页码
    	private Integer pageSize;//每页总数
    	private Integer pageCount;//全部记录
    	public Integer getCurrentPage() {
    		return currentPage;
    	}
    	public void setCurrentPage(Integer currentPage) {
    		this.currentPage = currentPage;
    	}
    	public Integer getPageSize() {
    		return pageSize;
    	}
    	public void setPageSize(Integer pageSize) {
    		this.pageSize = pageSize;
    	}
    	public Integer getPageCount() {
    		return pageCount;
    	}
    	public void setPageCount(Integer pageCount) {
    		this.pageCount = pageCount;
    	}
    	@Override
    	public String toString() {
    		return "Page [currentPage=" + currentPage + ", pageSize=" + pageSize + ", pageCount=" + pageCount + "]";
    	}
    	
    }
    
    
    package Mapper;
    
    import java.sql.Connection;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.util.Properties;
    
    import org.apache.ibatis.executor.statement.StatementHandler;
    import org.apache.ibatis.mapping.BoundSql;
    import org.apache.ibatis.plugin.Interceptor;
    import org.apache.ibatis.plugin.Intercepts;
    import org.apache.ibatis.plugin.Invocation;
    import org.apache.ibatis.plugin.Plugin;
    import org.apache.ibatis.plugin.Signature;
    import org.apache.ibatis.reflection.MetaObject;
    import org.apache.ibatis.reflection.SystemMetaObject;
    import org.apache.log4j.Logger;
    
    import Model.Page;
    
    @Intercepts({ @Signature(type = StatementHandler.class, method = "prepare", args = { Connection.class }) })
    public class pageInterceptor implements Interceptor {
    
    	private Page page = null;
    
    	private Logger logger = Logger.getLogger(pageInterceptor.class);
    
    	@Override
    	public Object intercept(Invocation invocation) throws Throwable {
    		// 获得源对象
    		StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
    		// 从源对象获得属性操作类
    		MetaObject m1 = SystemMetaObject.forObject(statementHandler);
    		// 多次循环分离出原始目标类
    		Object object = null;
    		while (m1.hasGetter("h")) {
    			object = m1.getValue("h");
    			m1 = SystemMetaObject.forObject(m1);
    		}
    		if (object == null)
    			object = statementHandler;// 如果为空证明压根就没有代理对象,即没有插件用它,
    		// 获取原始目标类的属性操作类
    		MetaObject m2 = SystemMetaObject.forObject(object);
    		while (m2.hasGetter("target")) {
    			object = m2.getValue("target");
    			m2 = SystemMetaObject.forObject(object);
    		}
    		// 计算总数sql
    		culCount((Connection) invocation.getArgs()[0], m2);
    		// 取出sql
    		String sql = (String) m2.getValue("delegate.boundSql.sql");// 取出属性,OGNL写法
    		sql = sql.trim();
    		String start = sql.substring(0, 5);
    		if (!start.equalsIgnoreCase(start))
    			return invocation.proceed();// 如果没有select 直接跳过
    		// 取出传进来的参数
    		BoundSql bsql = (BoundSql) m2.getValue("delegate.boundSql");
    		Page p = (Page) bsql.getParameterObject();
    		if (p.getCurrentPage() == null || p.getPageSize() == null)
    			// 重新拼接sql
    			sql = sql + " limit " + (page.getCurrentPage() - 1) * page.getPageSize() + "," + page.getPageSize();
    		else
    			sql = sql + " limit " + (p.getCurrentPage() - 1) * p.getPageSize() + "," + p.getPageSize();
    		p.setPageCount(page.getPageCount());
    		// 放置在boundsql里
    		m2.setValue("delegate.boundSql.sql", sql);
    		PreparedStatement preparedStatement = (PreparedStatement) invocation.proceed();
    		// 根据接口可以得知最后肯定返回的是一个Statement对象
    		return preparedStatement;
    	}
    
    	private void culCount(Connection connection, MetaObject m2) {
    		// 如果要执行一次查询 需要Connection Statement ResultSet
    		String sql = (String) m2.getValue("delegate.boundSql.sql");
    		sql = "select count(*) from (" + sql + ") $_paging";
    		try {
    			PreparedStatement preparedStatement = connection.prepareStatement(sql);
    			ResultSet resultSet = preparedStatement.executeQuery();
    			int count = 0;
    			if (resultSet.next()) {
    				count = resultSet.getInt(1);
    			}
    			page.setPageCount(count);
    		} catch (SQLException e) {
    			e.printStackTrace();
    		}
    	}
    
    	@Override
    	public Object plugin(Object target) {
    		// TODO Auto-generated method stub
    		if (target instanceof StatementHandler)
    			return Plugin.wrap(target, this);// 返回代理对象
    		return target;
    	}
    
    	@Override
    	public void setProperties(Properties properties) {
    		// TODO Auto-generated method stub
    		int currentPage = Integer.parseInt(properties.getProperty("currentPage"));
    		int pageSize = Integer.parseInt(properties.getProperty("pageSize"));
    		page = new Page();
    		page.setPageSize(pageSize);
    		page.setCurrentPage(currentPage);
    	}
    
    }
    
    

    <plugins>
      	<plugin interceptor="Mapper.pageInterceptor">
      		<property name="currentPage" value="1"/>
      		<property name="pageSize" value="5"/>
      	</plugin>
      </plugins>




    展开全文
  • 内存管理单元 MMU

    2016-09-26 15:19:48
    现代操作系统及CPU硬件中,都会提供内存管理单元(memory management unit,MMU)来进行内存的有效...各种算法都有其优缺点,为特定系统选择内存管理算法依赖于很多因素,特别是系统的硬件设计。 1 内存管理的目的

    转自http://www.cnitblog.com/tarius.wu/articles/322.html

    现代操作系统及CPU硬件中,都会提供内存管理单元(memory management unitMMU)来进行内存的有效管理。内存管理算法有许多,从简单的裸机方法到分页和分段策略。各种算法都有其优缺点,为特定系统选择内存管理算法依赖于很多因素,特别是系统的硬件设计。

    1 内存管理的目的

    内存管理的目的是为了更好的使用内存(似乎是废话-,-)。 内存是现代操作系统运行的中心。操作系统中任何一个进程的运行都需要内存,但是,操作系统中的内存是有限的;另一方面,从安全的角度出发,进程都需要有自 己的内存空间,其他的进程都不能访问这个私有的空间;同时,内存的分配会导致内存碎片问题,严重影响计算机的性能。以上这三个问题就是一般内存管理算法所 需要处理的目标。

    •   交换
    • 内存保护
    •   碎片问题

    2 交换

    进程需要在内存中执行,但进程可以暂时从内存中交换swap)出去到备份存储上,当需要时再调回到内存中去。

    m1.JPG

    在基于优先级的交换调度算法中,如果一个更高优先级的进程来了且需要服务,内存管理可以交换出低优先级的进程,以便装入和执行更高优先级的进程。当高优先级的进程执行完毕之后,低优先级的进程可以交换回内存继续执行。这种交换有时被称之为滚出(roll out)、滚进(roll in)

           通常一个交换出的进程需要交换回它原来的内存空间。这一限制是由地址捆绑方式决定的。如果捆绑是在汇编时或加载时决定的,那么就不可以移动到不同的位置。如果捆绑是在运行时决定,由于物理地址是在运行时才确定,那么进程可以移到不同的地址空间。

    交换的代价:交换时间

    交换时间主要是指转移时间,总的转移时间和所交换的内存空间成正比。交换不需要或只需要很少的磁头移动,简单的说,交换空间通常作为磁盘的一整块,且独立于文件系统(如Linuxswap空间),因此使用就有可能很快。

    交换需要花很多时间,而且进程执行时间却很少,故交换通常不执行,但只有在许多进程运行且内存吃紧时,交换才开始启动。

    3 分页

    3.1内存保护和内存碎片的背景

    内存保护是指操作系统进程不受用户进程的影响,保护用户进程不受其他用户进程的影响。内存保护最基本的思路是进程使用逻辑地址空间,而内存管理单元所看的是物理地址。操作系统将逻辑地址分配给进程,MMU负责逻辑地址到物理地址的映射(转换,捆绑)。

           值得注意的是对于指令(程序)和数据映射到内存地址可以在以下步骤地任意一步执行:

    • 编译时:如果编译时就知道进程将在内存中的驻留地址,那么就可以生成绝对代码。如MS-DOSCOM格式程序。
    • 加载时:如果编译时不知道程序将驻留在何处,那么编译器就必须要生成可重定位代码(relocatable code )。这种情况下,最后地址映射会延迟到加载时才确定,如果开始地址发生变换,必须重新加载程序,以引入新值。
    •  执行时:如果进程在执行时可以从一个内存段移到另一个内存段,那么映射必须延迟到执行时才进程。采用这种方法需要硬件的支持,目前绝大多数操作系统采用这种方法(基于分页、分段等)。

    内存碎片是操作系统内存分配的产物。最初操作系统的内存是连续分配的,即进程A需要某一大小的内存空间,如200KB,操作系统就需要找出一块至少200KB的连续内存空间给进程A。随着系统的运行,进程终止时它将释放内存,该内存可以被操作系统分配给输入队列里的其他等待内存资源的进程。

    可以想象,随着进程内存的分配和释放,最初的一大块连续内存空间被分成许多小片段,即使总的可用空间足够,但不再连续,因此产生的内存碎片。

    一 个办法是不再对内存空间进行连续分配。这样只要有物理内存就可以为进程进行分配。而实际上,不进行连续分配只是相对的,因为完全这样做的代价太大。现实 中,往往定出一个最小的内存单元,内存分配是这最小单元的组合,单元内的地址是连续的,但各个单元不一定连续。这样的内存小单元有页和段。

    当然,分段和分页也会产生碎片,但理论上每个碎片的大小不超过内存单元的大小。

    3.2 分页

    分页时一种内存管理方案,同时也提供了内存保护机制。它允许分配的物理内存地址可以是非连续的。

    逻辑内存分为大小相等块的组合,这个块称之为页;物理内存则分为固定大小的帧(frame)。页大小应和帧大小相同,这是由硬件决定的。通常是2的幂,这样可以方便地将逻辑地址映射到物理地址。

    基于分页的逻辑地址到物理地址的映射
    m2.JPG

    考虑32位地址。如果页大小是4KB,则需要12位来表示每一页中的某个具体地址,因此32位的逻辑地址中需要12位来对某一页中的具体地址寻址。这12位叫做页偏移。剩下的20位可以作为页码,可以有1M的页。逻辑地址可以表示为:
                    m4.JPG

    寻址时,根据页码P查页表,找到该页对应的帧,将帧号与页偏移(也是帧偏移)组合即得到物理地址。这样也说明了为什么页大小要等于帧大小,因为页数要等于帧数。

    例如,页大小为4K,页码11对应的帧码是10,即表示是第10块物理帧,也偏移为5,则逻辑地址0X0000b 005对应的物理地址是0X0000a 005

    3.3 分页的内存保护

    基于分页的操作系统在分配内存时分给进程所需要的页数,其对应物理内存的帧号同时装入该MMU的页表。同时页表上有一个标记为,指明该页是属于哪个进程的。甚至可以定义该页对于某个进程的读写权限。非法的读写操作会产生硬件陷阱(或内存保护冲突)。

    3.4 分页的代价

    由上一节可知分页是基于查找表的,而在内存中存储这个1M个项目的页表本身就带来了内存消耗和查找速度问题。于是,页表通常需要硬件的支持,即将页表写在硬件MMU的寄存器中。

    如果页表比较小,那么页表写在寄存器中可以加快查找速度。但绝大多数当代的计算机页表都非常大。对于这些页表,采用快速寄存器来实现页表就不太合理了。

    一种办法是使用TLBtranslation look-aside buffer)。TLB是关联的寄存器,TLB条目由两部分组成:页号和帧号。
    m5.JPG

    TLB只包含页表中的一小部分条目,整个页表还是保存在内存中。当CPU产生逻辑地址后,其页号提交给TLB。如果找到了页号,那同时也就找到了帧号,就可以访问物理内存;如果页号不在TLB中(称为TLB失效),那就需要访问页表。在页表中找到帧号后,把页号和帧号增加到TLB中,这样下次再用时可以很快找到。如果TLB中条目已满,则操作系统会根据一个替换策略来替换条目。替换策略有很多,从最近最小使用替换到随机替换等。另外,有的TLB允许某些条目不被替换,如内核代码的条目。

    有的TLB还在条目中保存地址空间保护标志符,用来唯一标志进程,以提供进程内存保护。

    3.5 页表结构

    对于32位以及64位逻辑地址的计算机来说,其页表实在太过庞大。为了压缩页表,一个简单的方法是使用层次化分页算法,就是将页表再分页。(这实际上是一种索引的方法)

    m6.JPG
    m7.JPG

    即将2^20个页表项分为2^10个组,每个组里面有2^10项。这样只需要2K*4=8K的页表空间,且查找速度也有很大提升。例如原先最坏情况下要查2^20次,现在最坏只要2*2^10

    
    展开全文
  • 内存管理单元-MMU

    2015-08-10 19:36:41
    各种算法都有其优缺点,为特定系统选择内存管理算法依赖于很多因素,特别是系统的硬件设计。 1 内存管理的目的 内存管理的目的是为了更好的使用内存(似乎是废话-,-)。内存是现代操作系统运行的中心。操作系统中...

    现代操作系统及CPU硬件中,都会提供内存管理单元(memory management unit,MMU)来进行内存的有效管理。内存管理算法有许多,从简单的裸机方法到分页和分段策略。各种算法都有其优缺点,为特定系统选择内存管理算法依赖于很多因素,特别是系统的硬件设计。

    1 内存管理的目的

    内存管理的目的是为了更好的使用内存(似乎是废话-,-)。内存是现代操作系统运行的中心。操作系统中任何一个进程的运行都需要内存,但是,操作系统中的内存是有限的;另一方面,从安全的角度出发,进程都需要有自己的内存空间,其他的进程都不能访问这个私有的空间;同时,内存的分配会导致内存碎片问题,严重影响计算机的性能。以上这三个问题就是一般内存管理算法所需要处理的目标。

    •   交换
    • 内存保护
    •   碎片问题

    2 交换

    进程需要在内存中执行,但进程可以暂时从内存中交换(swap)出去到备份存储上,当需要时再调回到内存中去。

    m1.JPG

    在基于优先级的交换调度算法中,如果一个更高优先级的进程来了且需要服务,内存管理可以交换出低优先级的进程,以便装入和执行更高优先级的进程。当高优先级的进程执行完毕之后,低优先级的进程可以交换回内存继续执行。这种交换有时被称之为滚出(roll out)、滚进(roll in)。

           通常一个交换出的进程需要交换回它原来的内存空间。这一限制是由地址捆绑方式决定的。如果捆绑是在汇编时或加载时决定的,那么就不可以移动到不同的位置。如果捆绑是在运行时决定,由于物理地址是在运行时才确定,那么进程可以移到不同的地址空间。

    交换的代价:交换时间

    交换时间主要是指转移时间,总的转移时间和所交换的内存空间成正比。交换不需要或只需要很少的磁头移动,简单的说,交换空间通常作为磁盘的一整块,且独立于文件系统(如Linux的swap空间),因此使用就有可能很快。

    交换需要花很多时间,而且进程执行时间却很少,故交换通常不执行,但只有在许多进程运行且内存吃紧时,交换才开始启动。

    3 分页

    3.1内存保护和内存碎片的背景

    内存保护是指操作系统进程不受用户进程的影响,保护用户进程不受其他用户进程的影响。内存保护最基本的思路是进程使用逻辑地址空间,而内存管理单元所看的是物理地址。操作系统将逻辑地址分配给进程,MMU负责逻辑地址到物理地址的映射(转换,捆绑)。

           值得注意的是对于指令(程序)和数据映射到内存地址可以在以下步骤地任意一步执行:

    • 编译时:如果编译时就知道进程将在内存中的驻留地址,那么就可以生成绝对代码。如MS-DOS的COM格式程序。
    • 加载时:如果编译时不知道程序将驻留在何处,那么编译器就必须要生成可重定位代码(relocatable code )。这种情况下,最后地址映射会延迟到加载时才确定,如果开始地址发生变换,必须重新加载程序,以引入新值。
    • 执行时:如果进程在执行时可以从一个内存段移到另一个内存段,那么映射必须延迟到执行时才进程。采用这种方法需要硬件的支持,目前绝大多数操作系统采用这种方法(基于分页、分段等)。

    内存碎片是操作系统内存分配的产物。最初操作系统的内存是连续分配的,即进程A需要某一大小的内存空间,如200KB,操作系统就需要找出一块至少200KB的连续内存空间给进程A。随着系统的运行,进程终止时它将释放内存,该内存可以被操作系统分配给输入队列里的其他等待内存资源的进程。

    可以想象,随着进程内存的分配和释放,最初的一大块连续内存空间被分成许多小片段,即使总的可用空间足够,但不再连续,因此产生的内存碎片。

    一个办法是不再对内存空间进行连续分配。这样只要有物理内存就可以为进程进行分配。而实际上,不进行连续分配只是相对的,因为完全这样做的代价太大。现实中,往往定出一个最小的内存单元,内存分配是这最小单元的组合,单元内的地址是连续的,但各个单元不一定连续。这样的内存小单元有页和段。

    当然,分段和分页也会产生碎片,但理论上每个碎片的大小不超过内存单元的大小。

    3.2 分页

    分页时一种内存管理方案,同时也提供了内存保护机制。它允许分配的物理内存地址可以是非连续的。

    逻辑内存分为大小相等块的组合,这个块称之为页;物理内存则分为固定大小的帧(frame)。页大小应和帧大小相同,这是由硬件决定的。通常是2的幂,这样可以方便地将逻辑地址映射到物理地址。

    基于分页的逻辑地址到物理地址的映射
    m2.JPG

    考虑32位地址。如果页大小是4KB,则需要12位来表示每一页中的某个具体地址,因此32位的逻辑地址中需要12位来对某一页中的具体地址寻址。这12位叫做页偏移。剩下的20位可以作为页码,可以有1M的页。逻辑地址可以表示为:
                    m4.JPG

    寻址时,根据页码P查页表,找到该页对应的帧,将帧号与页偏移(也是帧偏移)组合即得到物理地址。这样也说明了为什么页大小要等于帧大小,因为页数要等于帧数。

    例如,页大小为4K,页码11对应的帧码是10,即表示是第10块物理帧,也偏移为5,则逻辑地址0X0000b 005对应的物理地址是0X0000a 005。

    3.3 分页的内存保护

    基于分页的操作系统在分配内存时分给进程所需要的页数,其对应物理内存的帧号同时装入该MMU的页表。同时页表上有一个标记为,指明该页是属于哪个进程的。甚至可以定义该页对于某个进程的读写权限。非法的读写操作会产生硬件陷阱(或内存保护冲突)。

    3.4 分页的代价

    由上一节可知分页是基于查找表的,而在内存中存储这个1M个项目的页表本身就带来了内存消耗和查找速度问题。于是,页表通常需要硬件的支持,即将页表写在硬件MMU的寄存器中。

    如果页表比较小,那么页表写在寄存器中可以加快查找速度。但绝大多数当代的计算机页表都非常大。对于这些页表,采用快速寄存器来实现页表就不太合理了。

    一种办法是使用TLB(translation look-aside buffer)。TLB是关联的寄存器,TLB条目由两部分组成:页号和帧号。
    m5.JPG

    TLB只包含页表中的一小部分条目,整个页表还是保存在内存中。当CPU产生逻辑地址后,其页号提交给TLB。如果找到了页号,那同时也就找到了帧号,就可以访问物理内存;如果页号不在TLB中(称为TLB失效),那就需要访问页表。在页表中找到帧号后,把页号和帧号增加到TLB中,这样下次再用时可以很快找到。如果TLB中条目已满,则操作系统会根据一个替换策略来替换条目。替换策略有很多,从最近最小使用替换到随机替换等。另外,有的TLB允许某些条目不被替换,如内核代码的条目。

    有的TLB还在条目中保存地址空间保护标志符,用来唯一标志进程,以提供进程内存保护。

    3.5 页表结构

    对于32位以及64位逻辑地址的计算机来说,其页表实在太过庞大。为了压缩页表,一个简单的方法是使用层次化分页算法,就是将页表再分页。(这实际上是一种索引的方法)

    m6.JPG
    m7.JPG

    即将2^20个页表项分为2^10个组,每个组里面有2^10项。这样只需要2K*4=8K的页表空间,且查找速度也有很大提升。例如原先最坏情况下要查2^20次,现在最坏只要2*2^10次

    展开全文
  • 内存管理单元 MMU

    千次阅读 2008-02-25 19:53:00
    各种算法都有其优缺点,为特定系统选择内存管理算法依赖于很多因素,特别是系统的硬件设计。1 内存管理的目的内存管理的目的是为了更好的使用内存(似乎是废话-,-)。内存是现代操作系统运行的中心。操作系统中任何...
  • 转自 http://www.cnitblog.com/tarius.wu/articles/322.html 现代操作系统及CPU硬件中,都会提供内存管理单元(memory ...各种算法都有其优缺点,为特定系统选择内存管理算法依赖于很多因素,特别是系统的硬件设计。1
  • 首先明确为什么要使用分页查询,因为数据庞大,查询不可能全部显示在页面上,如果全部显示在页面上,也会造成查询速度... 两种分页各有优缺点,小伙伴们视具体情况使用吧。 下面要介绍的就是真分页方法: 1、建立Jav
  • 实验题目页面置换算法请求分页 实验目的 进一步理解父子进程之间的关系 理解内存页面调度的机理 掌握页面置换算法的实现方法 通过实验比较不同调度算法的优劣 培养综合运用所学知识的能力 页面置换算法是虚拟存储...
  • 第二十一讲 内存分区和分页 对程序进行分段处理,是由于程序本身的各段的特性决定的,在编译阶段完成; 将分割好的程序的各个段放入...分区的再次申请:这里涉及到算法,算法本身没有对错,只有优缺点;首先适配是找...
  • ##操作系统: 进程与线程的区别: 进程就是运行的一个程序,一个进程可以包含多个线程;进程是资源分配的最小单位,线程是CPU调度的最小单位。 线存共享 进程同步 ...进程之间的通信有哪些、各个优缺点
  • 3、存储过程的优缺点? 40 4、存储过程与函数的区别 41 5、索引的作用?和它的优点缺点是什么? 41 6、什么样的字段适合建索引 41 7、索引类型有哪些? 42 8、什么是事务?什么是锁? 42 9、什么叫视图?游标是什么...
  • •用分段方法分配管理作业,用分页方法分配管理内存; •兼有段式和页式管理的优点,系统复杂和开销增大,一般在大型机器上才使用。 第五章文件管理 1、文件管理任务与功能 任务:把存储、检索、...
  • 【数据结构】数组与链表的优缺点 139 【算法】什么是hash? 140 【算法】排序 141 【算法】冒泡排序 141 【算法】快速排序 142 【算法】归并排序的过程?时间复杂度?空间复杂度? 143 【算法】什么是一致性哈希?...
  • JAVA面试题最全集

    2010-03-13 13:09:10
    方法在垃圾收集器将对象从内存中清除出去之前做必要的清理工作。这个方法是由垃圾收集器在确定这个对象没有被引用时对这个对象调用的。它是在 Object 类中定义的,因此所有的类都继承了它。子类覆盖 finalize() ...
  • java面试题典 java 面试题 经典

    热门讨论 2010-06-18 13:42:36
    13. 解释归档和非归档模式之间的不同和它们各自的优缺点 31 14. 如何建立一个备份控制文件? 32 15. 给出数据库正常启动所经历的几种状态 ? 32 16. 哪个column可以用来区别V$视图和GV$视图? 32 17. 如何生成explain ...
  • java面试宝典

    2013-02-28 16:04:01
    199、在ORACLE大数据量下的分页解决方法。一般用截取ID方法,还有是三层嵌套方法。 47 200、xml有哪些解析技术?区别是什么? 48 201、你在项目中用到了xml技术的哪些方面?如何实现的? 48 202、用jdom解析xml文件时...
  • 千方百计笔试题大全

    2011-11-30 21:58:33
    199、在ORACLE大数据量下的分页解决方法。一般用截取ID方法,还有是三层嵌套方法。 47 200、xml有哪些解析技术?区别是什么? 48 201、你在项目中用到了xml技术的哪些方面?如何实现的? 48 202、用jdom解析xml文件时...
  • Java面试宝典2010版

    2011-06-27 09:48:27
    6、Struts优缺点 优点: 1. 实现MVC模式,结构清晰,使开发者只关注业务逻辑的实现. 7、STRUTS的应用(如STRUTS架构) 8、说说struts1与struts2的区别。 9、hibernate中的update()和saveOrUpdate()的区别,session的...
  • 最新Java面试宝典pdf版

    热门讨论 2011-08-31 11:29:22
    6、Struts优缺点 优点: 1. 实现MVC模式,结构清晰,使开发者只关注业务逻辑的实现. 120 7、STRUTS的应用(如STRUTS架构) 121 8、说说struts1与struts2的区别。 121 9、hibernate中的update()和saveOrUpdate()的区别,...
  • 6、Struts优缺点 优点: 1. 实现MVC模式,结构清晰,使开发者只关注业务逻辑的实现. 120 7、STRUTS的应用(如STRUTS架构) 121 8、说说struts1与struts2的区别。 121 9、hibernate中的update()和saveOrUpdate()的区别,...
  • asp.net知识库

    2015-06-18 08:45:45
    可按任意字段排序的分页存储过程(不用临时表的方法,不看全文会后悔) 常用sql存储过程集锦 存储过程中实现类似split功能(charindex) 通过查询系统表得到纵向的表结构 将数据库表中的数据生成Insert脚本的存储过程!!! ...
  • Java程序员面试宝典pdf

    热门讨论 2013-02-21 13:06:13
    面试题183 自己的最大优缺点是什么 336 面试题184 你希望的待遇为多少 336 面试题185 你认为团队工作和独自干活哪样效率更高 337 面试题186 如果你所处的团队中,并不是每个成员都承担着 相同的工作量,你会怎样看待...
  •  本书由多位工作在数据库维护一线的工程师合著而成,包含了精心挑选的数据库诊断案例与性能优化实践经验,内容涉及oracle典型错误的分析和诊断,各种sql优化方法(包括调整索引,处理表碎片,优化分页查询,改善...
  • C++程序员面试宝典

    热门讨论 2013-04-01 13:36:19
    面试题29 请描述一下你自己的优缺点 34 面试题30 你对本公司的了解有多少 34 面试题31 对这份工作的期望与目标何在 34 面试题32 你为什么要离职 34 面试题33 选择这份工作的原因是什么 35 面试题34 你认为相关产业的...
  • C#编程经验技巧宝典

    热门讨论 2008-06-01 08:59:33
    C#编程经验技巧宝典源代码,目录如下: 第1章 开发环境 1 <br>1.1 Visual Studio开发环境安装与配置 2 <br>0001 安装Visual Studio 2005开发环境须知 2 <br>0002 配置合适的Visual Studio 2005...
  • Java 面试宝典

    2013-02-01 10:02:08
    13、是否可以从一个 static 方法内部发出对非 static 方法的调用? ........................ 13 14、Integer 与 int 的区别 .....................................................................................
  • oracle的框架主要由物理结构、逻辑结构、内存分配、后台进程、oracle例程、系统改变号 (System Change Number)组成  物理结构 物理结构包含三种数据文件: 1) 控制文件 2) 数据文件 3) 在线重做日志文件  ...

空空如也

空空如也

1 2
收藏数 28
精华内容 11
关键字:

分页内存方法优缺点