供应商是否将new和malloc实施为小型对象分配器?

时间:2019-05-03 12:19:06

标签: c++ malloc new-operator dynamic-memory-allocation

是否允许实现new和/或malloc分配比请求更多的内存,这样可以避免以后的小分配产生开销?

根据我的经验,由于开销太大,因此没人在堆上分配单个对象,通常会写小对象分配器或在可能的地方简单地创建大数组。因此,针对程序员的实现方式感觉应该是易于实现的人体工程学/性能功能。

编译器已经这样做了吗,还是标准问题或其他问题阻止了这种情况?

3 个答案:

答案 0 :(得分:1)

  

编译器已经这样做了吗,还是标准问题或其他问题阻止了这种情况?

该标准不会阻止分配函数分配的空间超出要求的范围。它仅指出成功分配意味着分配的内存将至少与请求的大小一样。

引用C ++标准(n4659),

  

6.7.4.1分配功能[basic.stc.dynamic.allocation]
  ...
  2。分配功能尝试分配请求的存储量。 如果成功,它将返回存储块开始的地址。其字节长度至少应等于请求的大小。

答案 1 :(得分:1)

大多数操作系统[需要引用]以块(通常称为“页面”)的形式管理内存。这是底层硬件的产物。

一种长久以来的惯例是,库的malloc(并且扩展为new)可以通过从操作系统分配一个或多个内存“页面”来满足用户的内存请求。 ,然后将该内存分配给用户。(*)可以满足这种后续请求而不必从操作系统请求更多页面。

详细信息因系统和分配器而异。他们通常试图在速度(分配/释放)和效率(最小的内存使用)之间取得平衡。

传统上是具有特定内存要求(速度,效率)的应用程序一次完成malloc很大的内存,然后在其上进行该内存的管理拥有。这增加了复杂性,并增加了发生错误的机会(例如,通过应用程序的内存管理分配的内存free(),或者通过应用程序内存管理释放的内存malloc()释放但释放的内存,或者应用程序内存管理本身的错误) ),但允许应用程序控制使用的算法。

C ++通过allocators使此操作变得更容易,该方法有效地将容器的内存管理“外包”到另一个类,从而允许使用定制的,可重复使用的内存管理类。

所以:

  1. 是的,这是可能的。
  2. 不,标准中没有禁止的东西。
  3. 是的,通常已经在“幕后”完成了。

3的推论当然是古老的真理,即“衡量,优化,衡量”。(不要试图优化您没有的问题,如果有的话,使确保您的优化实际上改善了事情,而不是使事情变得更糟。)


(*)引入“页面”概念的硬件与确实保护彼此独立的应用程序的存储空间(即Memory Management Unit)相同。为避免应用程序破坏该保护,仅允许操作系统修改内存分配。术语和体系结构有所不同,但通常只有OS内核可以使用某种“监督模式”,因此应用程序必须触发内核,然后由内核进行分配,然后将控制权返回给应用程序。 >

这称为“上下文切换”,就CPU时间而言,它是其中最昂贵的操作之一。因此,从一开始,库实现者就开始寻找最小化上下文切换的方法。这就是为什么mallocnew通常已经针对一般用途进行了很好的优化。

答案 2 :(得分:0)

供应商(在这种情况下为libc-implementors,因为malloc / new通常是由您的标准库而不是由编译器提供程序真正实现的)会做各种事情,通常您可以期望进行某种小对象优化和最后分配大小的缓存至少不超过特定大小。

例如,这是我在Linux x86_64上使用libc进行gall-free时的libc计时,并且采用2幂次方:

else

和musl-libc一样:

    static func saveOrder(orderId: String, orderDate: String, customerName: String, orderPrice: String, itemsIdList: String, itemsList: String) throws {
        let context = CoreData.databaseContext
        let userRequest: NSFetchRequest<User> = User.fetchRequest()
        do {
            let userFetch = try context.fetch(userRequest)
            print("@@@@@@@@@@@@@@@@@@       fetching user")
            for userValue in userFetch {
                if userValue.name == UserDetails.fullName {
                    print("User is: \(userValue.name!)")  //correct
                    let orderRequest: NSFetchRequest<Order> = Order.fetchRequest()
                    let predicate = NSPredicate(format: "orderId == %@", orderId)
                    orderRequest.predicate = predicate
//                    orderRequest.fetchLimit = 1
                    do{
                        let orderFetch = try context.fetch(orderRequest)
//                        if orderFetch.count == 0 {
                        for order in orderFetch {
                            if order.orderId == orderId {
                                print("Order is already saved")
                                return
                            } else {
                                    print("@@@@@@@@@@@@    order is new")
                                    if #available(iOS 10.0, *) {
                                        let order = Order(context: context)
                                        order.user?.name = userValue.name!
                                        order.orderId = orderId
                                        order.orderDate = orderDate
                                        order.customerName = customerName
                                        order.orderPrice = orderPrice
                                        order.itemsIdList = itemsIdList
                                        order.itemsList = itemsList
                                        userValue.addToOrders(order)
                                        print("Order is: \(order)")
                                        let actions: [UNNotificationAction] = [UNNotificationAction(identifier: "chiudi", title: "Chiudi", options: [.foreground])]
                                        Notifications.newTimeIntervalNotification(notificationType: "New order", actions: actions, categoyIdentifier: "New order", title: "Ordine", body: "Hai un nuovo ordine", userInfo: [:] , timeInterval: 5, repeats: false)
                                        // modify inventory
                                        var productIdListArray:[String] = itemsIdList.components(separatedBy: ",")
                                        var productNameListArray:[String] = itemsList.components(separatedBy: ",")
                                        print("productIdListArray is : \(productIdListArray)")
                                        for product in 0..<productIdListArray.count {
//                                        for product in productIdListArray {
                                            do {
                                                try Product.decrementIventory(completed: { (true) in
                                                    // create an item entry in Core Data for each item in current order
//                                                    let  item = Item(context: context)
//                                                    item.order?.user?.name = userValue.name!
//                                                    item.itemId = productIdListArray[product]
//                                                    item.itemName = productNameListArray[product]
//                                                    order.addToItems(item)

                                                    print("Inventory seccessfully updated for product: \(productNameListArray[product])")
                                                }, productId: productIdListArray[product])
                                            } catch {print("Error in decrementing inventory : \(error)")
                                            }
                                        }
                                    } else {
                                        // Fallback on earlier versions
                                        let entityDescription = NSEntityDescription.entity(forEntityName: "Order", in: context)
                                        let order = Order(entity: entityDescription!, insertInto: context)
                                        order.user?.name = userValue.name!
                                        order.orderId = orderId
                                        order.orderDate = orderDate
                                        order.customerName = customerName
                                        order.orderPrice = orderPrice
                                        order.itemsIdList = itemsIdList
                                        order.itemsList = itemsList
                                        userValue.addToOrders(order)
                                        Notifications.newTimeIntervalNotification(notificationType: "New order", actions: [], categoyIdentifier: "New order", title: "Ordine", body: "Hai un nuovo ordine", userInfo: [:], timeInterval: 5, repeats: false)
                                        var productIdListArray:[String] = itemsIdList.components(separatedBy: ",")
                                        var productNameListArray:[String] = itemsList.components(separatedBy: ",")
                                        for product in 0..<productIdListArray.count {
                                            do {
                                                try Product.decrementIventory(completed: { (true) in

                                                    // create an item entry in Core Data for each item in current order
//                                                    let entityDescription = NSEntityDescription.entity(forEntityName: "Item", in: context)
//                                                    let item = Item(entity: entityDescription!, insertInto: context)
//                                                    item.order?.user?.name = userValue.name!
//                                                    item.itemId = productIdListArray[product]
//                                                    item.itemName = productNameListArray[product]
//                                                    order.addToItems(item)

                                                    print("Order.saveOrder: Inventory seccessfully updated for product: \(productNameListArray[product])")
                                                }, productId: productIdListArray[product])
                                            } catch {print("Error in decrementing inventory : \(error)")
                                            }
                                        }
                                    } // en of iOS 9 check
                            } // end of if order.orderId == orderId {} else {
                        } // end of for in
                    } catch {
                        print("Order.saveOrder():Error in fetching orders: \(error)")
                    }
                }
            }
        } catch {
            print("Error in fetching user: \(error)")
        }
        do {
            try context.save()
            print("@@@@@@@@@@@@ Order.saveOrder():   New order is saved do CoreData")

        } catch  {
            print("@@@@@@@@@@@@@@  Order.saveOrder():  Error saving new order to CoreData: \(error)")
        }
    }

如您所见,小尺寸在一定程度上进行了优化,但是在不同的实现方式上有所不同(无多线程的无malloc也有很大不同)。

如果您确实关心某些特定的小型分配,那么最好使用自己的空闲列表分配器,无论后端如何,都获得最佳的速度/内存使用率。